home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 January: Technology Seed / Jan. '98 ATS.toast / NavServices1.0b3 / Navigation Services SDK / Examples / SimpleText / SimpleText ƒ / GXFile.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-01-12  |  95.6 KB  |  3,236 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        GXFile.c
  3.  
  4.     Contains:    xxx put contents here xxx
  5.  
  6.     Version:    xxx put the technology version here xxx
  7.  
  8.     Copyright:    © 1997 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     File Ownership:
  11.  
  12.         DRI:                Yan Arrouye
  13.  
  14.         Other Contact:        xxx put alternate contact (owner’s functional manager) here xxx
  15.  
  16.         Technology:            xxx put the technology group name here xxx
  17.  
  18.     Writers:
  19.  
  20.         (Yan)    Yan Arrouye
  21.  
  22.     Change History (most recent first):
  23.  
  24.          <2>      5/8/97    Yan        Use NavCompleteSave
  25. */
  26.  
  27. /*
  28.     File:        GXFile.c
  29.  
  30.     Contains:    GX print file support for simple text application.
  31.  
  32.     Version:    SimpleText 1.4 or later
  33.  
  34. ** Copyright 1993-1996 Apple Computer. All rights reserved.
  35. **
  36. **    You may incorporate this sample code into your applications without
  37. **    restriction, though the sample code has been provided "AS IS" and the
  38. **    responsibility for its operation is 100% yours.  However, what you are
  39. **    not permitted to do is to redistribute the source as "DSC Sample Code"
  40. **    after having made changes. If you're going to re-distribute the source,
  41. **    we require that you make it clear in the source that the code was
  42. **    descended from Apple Sample Code, but that you've made changes.
  43.  
  44. */
  45.  
  46. #include "MacIncludes.h"
  47.  
  48. #include "GXFile.h"
  49.  
  50.  
  51. #include "NavigationServicesSupport.h"
  52.  
  53.  
  54. #pragma segment GXFile
  55.  
  56.  
  57.  
  58. // --------------------------------------------------------------------------------------------------------------
  59. // PRIVATE TYPEDEFS AND DECLARES
  60. // --------------------------------------------------------------------------------------------------------------
  61. // items to the left of the horizontal scroll bar
  62. #define kScrollAreaWidth    120
  63. #define kPageControlsWidth    32
  64. #define kZoomControlsWidth    26
  65. #define kToolControlWidth    16
  66.  
  67. // items in the pop up page selection window
  68. #define kPageSliderHeight    10
  69. #define kPageSliderMargins    7
  70. #define kPageThumbEdge        4
  71. #define kPageThumbHeight    (kPageSliderHeight + kPageThumbEdge*2)
  72. #define kPageThumbWidth        (kPageThumbHeight / 2)
  73. #define kPageThumbMargins    3
  74. #define kProxyHeight        150
  75. #define kProxyWidth            150
  76. #define kPopUpWindowHeightSmall    (kPageThumbHeight + kPageSliderMargins*2 + kPageThumbEdge*2)
  77. #define kPopUpWindowHeightLarge    (kPageThumbHeight + kPageSliderMargins*3 + kPageThumbEdge*2 + kProxyHeight)
  78.  
  79. #define kMinGXDocSize        kMinDocSize
  80.  
  81. // PICT proxies for the pages
  82. #define kProxyBaseID        (gxPrintingTagID)
  83. #define kProxyType            'prxy'
  84.  
  85. // flattened GX shapes for annotations
  86. #define kAnnotationBaseID    (gxPrintingTagID)
  87. #define kAnnotationType        'anot'
  88.  
  89. // table of pop up menu items and corosponding zoom factors
  90. typedef struct
  91.     {
  92.     short    menuItem;
  93.     Fixed    zoomFactor;
  94.     } ZoomTableEntry;
  95.     
  96. typedef struct
  97.     {
  98.     short    theFont;
  99.     short    theSize;
  100.     } TextState;
  101.     
  102. typedef struct  
  103.     {
  104.     gxSpoolBlock    spool;
  105.     long            reference;
  106.     long            position;
  107.     long            size;
  108.     void            *data;
  109.     void            *userField;
  110.     } userSpool;
  111.  
  112. #define LONGALIGN(n)        (((n) + 3) & ~3L)
  113. #define kAtomHeaderSize        (sizeof(Size) + sizeof(OSType))
  114. #define ABS(n)                (((n) < 0) ? -(n) : (n))
  115.  
  116. #if GENERATINGCFM
  117.     extern pascal OSErr SetImageDescriptionExtension(ImageDescriptionHandle desc, Handle extension, long idType);
  118. #endif
  119.  
  120.  
  121.  
  122. // --------------------------------------------------------------------------------------------------------------
  123. // FORWARD DECLARES
  124. // --------------------------------------------------------------------------------------------------------------
  125. OSErr    GXGetDocumentRect(WindowRef pWindow, WindowDataPtr pData, 
  126.             LongRect * documentRectangle, Boolean forGrow);
  127. OSErr    GXCommand(WindowRef pWindow, WindowDataPtr pData, short commandID, long menuResult);
  128.  
  129. // --------------------------------------------------------------------------------------------------------------
  130. // LOCAL GLOBALS
  131. // --------------------------------------------------------------------------------------------------------------
  132. static ZoomTableEntry gZoomTable[] = {
  133.                                 {i50,     0x8000},
  134.                                 {i100,    ff(1)},
  135.                                 {i112,    0x00011EB8},
  136.                                 {i150,     0x00018000},
  137.                                 {i200,    ff(2)},
  138.                                 {i400,    ff(4)},
  139.                                 {0,0}};
  140.  
  141.  
  142. // --------------------------------------------------------------------------------------------------------------
  143. // PRIVATE ROUTINES
  144. // --------------------------------------------------------------------------------------------------------------
  145.  
  146. static void GetCurrentPageAndPaper(WindowDataPtr pData, gxRectangle *pPageSize, gxRectangle *pPaperSize)
  147. {
  148.     GXGetFormatDimensions( ((GXDataPtr)pData)->currentPageFormat, pPageSize, pPaperSize);    
  149.     if (((GXDataPtr)pData)->dontShowMargins)
  150.         *pPaperSize = *pPageSize;
  151.         
  152. } // GetCurrentPageAndPaper
  153.  
  154. // ------------------------------------------------------------------------------------------------------
  155. static void InitColorMatrix(Fixed m[5][4])
  156. {
  157.     register Fixed *x;
  158.     register short i;
  159.  
  160.     x = &m[0][0];
  161.     for(i = 19; i>=0; i--)
  162.         *x++ = 0;
  163.     m[0][0] = m[1][1] = m[2][2] = m[3][3] = fixed1;           /* Identity matrix, for cleanliness */
  164.     
  165. } // InitColorMatrix
  166.  
  167. // --------------------------------------------------------------------------------------------------------------
  168. static void RectangleToRect(const gxRectangle* gxr, Rect* qdr)
  169. {
  170.     qdr->left = FixedRound(gxr->left);
  171.     qdr->top = FixedRound(gxr->top);
  172.     qdr->right = FixedRound(gxr->right);
  173.     qdr->bottom = FixedRound(gxr->bottom);
  174.     
  175. } // RectangleToRect
  176.  
  177. // --------------------------------------------------------------------------------------------------------------
  178. #define allocationIncrement   1024     /* the storage handle is grown by this amount */
  179.  
  180. static long HandleSpoolProc(gxSpoolCommand command,  userSpool *block)
  181. {
  182.     gxGraphicsError    anErr = noErr;
  183.     
  184.        switch (command)
  185.            {
  186.           case gxOpenReadSpool:
  187.              block->size = 0;
  188.              block->position = 0;
  189.               break;
  190.       
  191.           case gxOpenWriteSpool:
  192.              block->data = NewHandle(allocationIncrement);
  193.              block->size = allocationIncrement;
  194.              block->position = 0;
  195.             anErr = MemError();
  196.               break;
  197.       
  198.           case gxReadSpool:
  199.              BlockMoveData((*(char **) block->data) + block->position, block->spool.buffer, block->spool.count);
  200.              block->position += block->spool.count;
  201.               break;
  202.  
  203.           case gxWriteSpool:
  204.               {  
  205.             register long oldPosition;
  206.  
  207.             oldPosition = block->position;
  208.             block->position += block->spool.count;
  209.  
  210.             /* make sure there is at least enough room for one buffer size past current pointer */
  211.             if (block->position + block->spool.bufferSize > block->size)      
  212.                  {
  213.                 block->size += block->spool.bufferSize;
  214.                 HUnlock((Handle) block->data);
  215.                 SetHandleSize((Handle) block->data, block->size);
  216.                 anErr = MemError();
  217.                 HLock((Handle) block->data);
  218.                  }
  219.             if (anErr == noErr)
  220.                  BlockMoveData(block->spool.buffer, (*(char **) block->data + oldPosition), block->spool.count);
  221.               }
  222.               break;
  223.       
  224.           case gxCloseSpool:
  225.              SetHandleSize((Handle) block->data, block->position);
  226.               break;
  227.            }
  228.         
  229.    return anErr;
  230.    
  231. } // HandleSpoolProc
  232.  
  233. #if GENERATINGCFM
  234.     static RoutineDescriptor gHandleSpoolProcRD = BUILD_ROUTINE_DESCRIPTOR(uppgxSpoolProcInfo, HandleSpoolProc);
  235.     static gxSpoolUPP gHandleSpoolProc = &gHandleSpoolProcRD;
  236. #else
  237.     static gxSpoolUPP gHandleSpoolProc = NewgxSpoolProc(HandleSpoolProc);
  238. #endif
  239.  
  240. // --------------------------------------------------------------------------------------------------------------
  241. static long* AppendAtom(long stream[], Size size, OSType tag, const void* data)
  242. {
  243.  
  244.     *stream++    = size + kAtomHeaderSize;
  245.     *stream++    = tag;
  246.     BlockMoveData(data, (Ptr)stream, size);
  247.  
  248.     return (long*)((char*)stream + size);
  249.     
  250. } // AppendAtom
  251.  
  252. // --------------------------------------------------------------------------------------------------------------
  253. static Handle CreateQDGXStream(gxShape source, PicHandle proxie, Boolean forPrintingOnly, Boolean eraseBackground)
  254. /*
  255.  *    See the comment on DecompressShape for an explaination of the parameters.
  256.  *    This routine is used by both DecompressShape for embedding shapes in PICTs,
  257.  *    and AddQDGXRecorderFrame for making gx movies.
  258. */
  259. {
  260.     #define            gxForPrintingOnlyAtom    'fpto'
  261.     #define            gxEraseBackgroundAtom    'erbg'
  262.  
  263.     long            atomCount, shapeSize, proxieSize, dataSize, fontListSize;
  264.     Handle            dataHdl, shapeHdl;
  265.     gxFlatFontList*    fontList;
  266.     gxTag            fontListTag;
  267.       userSpool         block;
  268.  
  269.     block.spool.spoolProcedure = gHandleSpoolProc;
  270.     block.spool.buffer = nil;
  271.     block.spool.bufferSize = 0;
  272.     GXFlattenShape(source, gxFontListFlatten | gxFontGlyphsFlatten | gxFontVariationsFlatten, &block.spool);
  273.     shapeHdl = (Handle) block.data;
  274.     if (shapeHdl == nil)
  275.         return nil;
  276.  
  277.     if (proxie)
  278.         {    
  279.         atomCount = 2;
  280.         proxieSize = LONGALIGN(GetHandleSize((Handle)proxie));
  281.         }
  282.     else
  283.         {    
  284.         atomCount = 1;
  285.         proxieSize = 0;
  286.         }
  287.     shapeSize = LONGALIGN(GetHandleSize(shapeHdl));
  288.  
  289.     if (forPrintingOnly)
  290.         ++atomCount;
  291.     if (eraseBackground)
  292.         ++atomCount;
  293.  
  294.     fontListSize = 0;
  295.     fontList = nil;
  296.     GXIgnoreGraphicsWarning(count_out_of_range);
  297.     if (GXGetShapeTags(source, gxFlatFontListItemTag, 1, 1, &fontListTag) > 0)
  298.         {    
  299.         fontListSize = GXGetTag(fontListTag, nil, nil);
  300.         if (fontListSize > 0)
  301.             {    
  302.             fontList = (gxFlatFontList*)NewPtr(fontListSize);
  303.             if (fontList != nil)
  304.                 {    
  305.                 GXGetTag(fontListTag, nil, fontList);
  306.                 fontListSize = LONGALIGN(fontListSize);
  307.                 ++atomCount;
  308.                 }
  309.             else
  310.                 fontListSize = 0;
  311.             }
  312.         }
  313.     GXPopGraphicsWarning();        // count_out_of_range
  314.  
  315.     dataSize = atomCount * kAtomHeaderSize + shapeSize + proxieSize + fontListSize + sizeof(long);
  316.     dataHdl = NewHandle(dataSize);
  317.     if (dataHdl == nil)
  318.         {    
  319.         DisposeHandle(shapeHdl);
  320.         if (fontList)
  321.             DisposePtr((Ptr)fontList);
  322.         return nil;
  323.         }
  324.     
  325.     {    
  326.         long* p = (long*)*dataHdl;
  327.  
  328.         if (forPrintingOnly)
  329.             p = AppendAtom(p, 0, gxForPrintingOnlyAtom, nil);
  330.         if (eraseBackground)
  331.             p = AppendAtom(p, 0, gxEraseBackgroundAtom, nil);
  332.         if (proxie)
  333.             p = AppendAtom(p, proxieSize, 'PICT', *proxie);
  334.         if (fontList)
  335.             p = AppendAtom(p, fontListSize, gxFlatFontListItemTag, fontList);
  336.         p = AppendAtom(p, shapeSize, 'qdgx', *shapeHdl);
  337.         *p++ = 0;        // end of the atom-list
  338.  
  339.         DisposeHandle(shapeHdl);
  340.         if (fontList)
  341.             DisposePtr((Ptr)fontList);
  342.     }
  343.     return dataHdl;
  344.  
  345. } // CreateQDGXStream
  346.  
  347. // --------------------------------------------------------------------------------------------------------------
  348. static PicHandle DecompressShape(gxShape theShape, PicHandle proxie, Boolean forPrintingOnly, Boolean eraseBackground)
  349. /*
  350.  *    This guy returns a Quickdraw picture containing an embedded shape, and a proxie
  351.  *    of the shape, if proxie is not nil. This is called by ShapeToScrap and DragAndDropShape.
  352.  *
  353.  *    theShape            • the shape you want to embedd in a PICT
  354.  *    proxie            • a PICT to be drawn if theShape cannot be drawn (optional but recommended)
  355.  *    forPrintingOnly        • if TRUE, then the decompressor will always look for the proxie
  356.  *                    and theShape will only be used when printing. Use this setting if
  357.  *                    theShape might be too large or too slow when drawn from other apps.
  358.  *                    • If FALSE, then the decompressor will draw theShape unless it
  359.  *                    gets an error, in which case it will look for a proxie.
  360.  *    eraseBackground    • if TRUE, the decompressor will always erase the background to WHITE
  361.  *                    before drawing the shape. This is slower, but needed if the shape does not
  362.  *                    fill its bounding rectangle.
  363.  *                    • if FALSE, the decompressor will just draw the shape. Use this setting
  364.  *                    if the shape entirely fills its bounding rectangle.
  365.  *
  366.  *    The shape [and proxie] is embedded by constructing a stream of atoms. Each atom begins
  367.  *    with a size (long) and a type (OSType) and then the data for that type. After the last atom,
  368.  *    there is a trailing zero (long) to mark the end of the stream. For embedded shapes, the type
  369.  *    is 'qdgx', and for the proxie the type is 'PICT'. Note that the size fields are rounded up to
  370.  *    a multiple of 4. Finally, to alert QuickTime that the data is in this parsable form with a
  371.  *    possible PICT proxie, we add a 'prxy' extension to the ImageDescriptionHandle.
  372.  *
  373.  *    Picture of this form will draw the embedded shape when an application calls DrawPicture
  374.  *    if GX is around, and if not, the proxie will be drawn. When printed, the shape or the proxie
  375.  *    will be printed. This is meant to replace the PicComment described in GX 1.0 for embedding
  376.  *    shapes in pictures.
  377.  *
  378.  *    If you want to include a flatFontList tag, be sure that theShape is a picture, otherwise GX will
  379.  *    not return the tag after GXFlattenShape. The flatFontList tag makes certain printing conditions
  380.  *    more efficient (i.e. font downloading to postscript printers).
  381.  *
  382.  *    Your shape must not contain a gxQuickDrawPictTag, meaning it contains embedded QD data, becuase
  383.  *    this will potentially crash when it tries to print. To fix that, DecompressShape looks for occurrances
  384.  *    of the tag, and converts them to real gx data by calling GXSetShapeType(shape, gxPictureType).
  385. */
  386. {
  387.     PicHandle                thePicture;
  388.     ImageDescriptionHandle    descHdl;
  389.     ImageDescriptionPtr        descPtr;
  390.     Handle                    dataHdl;
  391.  
  392.     if (!gMachineInfo.haveQuickTime)
  393.         return nil;
  394.  
  395.     /*
  396.      *    Move the shape's topLeft to 0,0 so that it draws neatly inside the picture frame.
  397.      *    Note that the qdgx movie library does not move the shape, since the shape may not
  398.      *    take up the whole frame.
  399.     */
  400.     {    
  401.         gxRectangle    bounds;
  402.  
  403.         GXGetShapeLocalBounds(theShape, &bounds);
  404.         if (bounds.left || bounds.top)
  405.             GXMoveShape(theShape, -bounds.left, -bounds.top);
  406.         dataHdl = CreateQDGXStream(theShape, proxie, forPrintingOnly, eraseBackground);
  407.         if (bounds.left || bounds.top)
  408.             GXMoveShape(theShape, bounds.left, bounds.top);
  409.     }
  410.     if (dataHdl == nil)
  411.         return nil;
  412.  
  413.     descHdl = (ImageDescriptionHandle)NewHandleClear(sizeof(ImageDescription));
  414.     if (descHdl)
  415.         {    
  416.         Rect            shortBounds;
  417.         gxRectangle    bounds;
  418.  
  419.         GXGetShapeLocalBounds(theShape, &bounds);
  420.         RectangleToRect(&bounds, &shortBounds);
  421.         OffsetRect(&shortBounds, -shortBounds.left, -shortBounds.top);    // set the topLeft of the src to 0,0
  422.         thePicture = OpenPicture(&shortBounds);
  423.  
  424.         descPtr = *descHdl;
  425.         descPtr->idSize = sizeof(ImageDescription);
  426.         descPtr->cType = 'qdgx';
  427.         descPtr->vendor = 'appl';
  428.         descPtr->temporalQuality = codecLosslessQuality;
  429.         descPtr->width = shortBounds.right;
  430.         descPtr->height = shortBounds.bottom;
  431.         descPtr->hRes = descPtr->vRes = ff(72);
  432.         descPtr->dataSize = GetHandleSize(dataHdl);
  433.         descPtr->frameCount = 1;
  434.         descPtr->depth = 32;
  435.         descPtr->clutID = -1;
  436.  
  437.         //    If there is a PICT proxie, add an image extension to tell QuickTime, in case GX is not around.
  438.         if (proxie)
  439.             {    
  440.             Handle prxyVersionHdl = NewHandle(sizeof(long));
  441.  
  442.             if (prxyVersionHdl != nil)
  443.                 {    
  444.                 *(long*)*prxyVersionHdl = 0;        // version number for 'prxy' extension
  445.                 #if GENERATINGCFM
  446.                     SetImageDescriptionExtension(descHdl, prxyVersionHdl, 'prxy');
  447.                 #else
  448.                     AddImageDescriptionExtension(descHdl, prxyVersionHdl, 'prxy');
  449.                 #endif
  450.                 }
  451.             }
  452.  
  453.         HLock(dataHdl);
  454.         DecompressImage(*dataHdl, descHdl, ((CGrafPtr)qd.thePort)->portPixMap, &shortBounds, &shortBounds, srcCopy, nil);
  455.         DisposeHandle((Handle)descHdl);
  456.         ClosePicture();
  457.         }
  458.     else
  459.         thePicture = nil;
  460.  
  461.     DisposeHandle(dataHdl);
  462.  
  463.     return thePicture;
  464.     
  465. } // DecompressShape
  466.  
  467. // --------------------------------------------------------------------------------------------------------------
  468. static PicHandle ShapeToPICT(gxShape source)
  469. /*
  470.  *    This guy returns a Quickdraw picture containing a 1-bit bitmap of the shape.
  471.  *    This is used by ShapeToScrap to create a proxie when calling DecompressShape.
  472.  *    If you want to make the proxie prettier (and larger), change the bitmap to 8-bit.
  473.  *    However, if you're using this in conjunction with DecompressShape to place a
  474.  *    gxShape on the clipboard, 1-bit should be enough, since the actual shape will be
  475.  *    drawn, rather than the proxie (unless forPrintingOnly is true).
  476. */
  477. {
  478.     gxRectangle        bounds;
  479.     gxShape            bitShape;
  480.     gxBitmap        bitmap;
  481.     PicHandle        thePicture;
  482.     Rect            shortBounds;
  483.  
  484.     /*
  485.      *    GetShapeLocalBounds doesn't accurately report the bounds of a gxQuickDrawPictTag.
  486.      *    but we should have none of them at this point anyway.
  487.     */
  488.     GXGetShapeLocalBounds(source, &bounds);
  489.     RectangleToRect(&bounds, &shortBounds);
  490.     OffsetRect(&shortBounds, -shortBounds.left, -shortBounds.top);
  491.  
  492.     bitmap.width        = shortBounds.right;
  493.     bitmap.height        = shortBounds.bottom;
  494.     bitmap.rowBytes        = bitmap.width + 31 >> 5 << 2;
  495.     bitmap.pixelSize    = 1;
  496.     bitmap.space        = gxIndexedSpace;
  497.     bitmap.set            = nil;
  498.     bitmap.profile        = nil;
  499.     bitmap.image        = NewPtrClear(bitmap.rowBytes * bitmap.height);
  500.     if (bitmap.image == nil)
  501.         return nil;
  502.  
  503.     bitShape = GXNewBitmap(&bitmap, nil);
  504.     if (bitShape != nil)
  505.         {    
  506.         gxViewGroup group    = GXNewViewGroup();
  507.         gxViewDevice device    = GXNewViewDevice(group, bitShape);
  508.         gxViewPort port        = GXNewViewPort(group);
  509.         gxTransform trans    = GXCloneTransform(GXGetShapeTransform(source));
  510.  
  511.         GXSetShapeAttributes(source, GXGetShapeAttributes(source) | gxMapTransformShape);
  512.         GXMoveShape(source, -bounds.left, -bounds.top);
  513.         GXSetViewPortDither(port, 4);
  514.         GXSetShapeViewPorts(source, 1, &port);
  515.         GXDrawShape(source);
  516.         GXSetShapeTransform(source, trans);
  517.         GXDisposeTransform(trans);
  518.         
  519.         GXDisposeViewGroup(group);    /* this disposes the gxViewPort and gxViewDevice */
  520.         GXDisposeShape(bitShape);
  521.         }
  522.  
  523.     {    
  524.         GrafPtr    thePort;
  525.         BitMap    srcBits;
  526.     
  527.         GetPort(&thePort);
  528.         srcBits.baseAddr = bitmap.image;
  529.         srcBits.rowBytes = bitmap.rowBytes;
  530.         srcBits.bounds = shortBounds;
  531.  
  532.         thePicture = OpenPicture(&shortBounds);
  533.         CopyBits(&srcBits, &thePort->portBits, &shortBounds, &shortBounds, srcOr, nil);
  534.         ClosePicture();
  535.     }
  536.     
  537.     DisposePtr((Ptr)bitmap.image);
  538.     
  539.     return thePicture;
  540.     
  541. } // ShapeToPICT
  542.  
  543.  
  544.  
  545. // --------------------------------------------------------------------------------------------------------------
  546.  
  547. static void GetRidOfAnyQDShapeTags(gxShape shape)
  548. {
  549.     gxShapeType shapeType = GXGetShapeType(shape);
  550.  
  551.     if (shapeType == gxPictureType)
  552.         {    
  553.         long        index, count;
  554.         gxShape        contentShape;
  555.     
  556.         count = GXGetPicture(shape, nil, nil, nil, nil);
  557.         for (index = 0; index < count; index++)
  558.             {
  559.             GXGetPictureParts(shape, index+1, 1, &contentShape, nil, nil, nil);
  560.             GetRidOfAnyQDShapeTags(contentShape);
  561.             }
  562.         }
  563.     else 
  564.         {
  565.         if ( (shapeType == gxRectangleType) && (GXGetShapeTags(shape, gxQuickDrawPictTag, 1, gxSelectToEnd, nil) > 0) )
  566.             GXSetShapeType(shape, gxPictureType);
  567.         }
  568.             
  569. } // GetRidOfAnyQDShapeTags
  570.  
  571. // --------------------------------------------------------------------------------------------------------------
  572.  
  573. static void ShapeToScrap(gxShape source)
  574. /*
  575.  *    This guy puts a Quickdraw picture on the clipboard containing an embedded shape
  576.  *    and, if addProxie is true, a 1-bit bitmap of the shape. Call this in response to
  577.  *    the user choosing "Copy" or "Cut" from the Edit menu. See comment for DecompressShape
  578.  *    to explain forPrintingOnly.
  579. */
  580. {
  581.     PicHandle    picture, proxy;
  582.     
  583.     proxy = ShapeToPICT(source);
  584.     picture = DecompressShape(source, proxy, false, true);
  585.     if (proxy)
  586.         KillPicture(proxy);
  587.  
  588.     if (picture)
  589.         {    
  590.         HLock((Handle)picture);
  591.         ZeroScrap();
  592.         PutScrap(GetHandleSize((Handle)picture), 'PICT', (Ptr)*picture);
  593.         KillPicture(picture);
  594.         }
  595.         
  596. } // ShapeToScrap
  597.  
  598. // --------------------------------------------------------------------------------------------------------------
  599.  
  600. static void CullShape(gxShape shape, gxShape addToThis, gxRectangle *pCullRect, gxStyle cullStyle, gxInk cullInk, gxTransform cullTransform)
  601. /*
  602.     Add to "addToThis" the "shape", only if the shape intersects the pCullRect.
  603. */
  604. {
  605.     gxShapeType shapeType = GXGetShapeType(shape);
  606.  
  607.     if (shapeType == gxPictureType)
  608.         {    
  609.         long        index, count;
  610.         gxShape        contentShape;
  611.     
  612.         count = GXGetPicture(shape, nil, nil, nil, nil);
  613.         for (index = 0; index < count; index++)
  614.             {
  615.             GXGetPictureParts(shape, index+1, 1, &contentShape, &cullStyle, &cullInk, &cullTransform);
  616.             CullShape(contentShape, addToThis, pCullRect, cullStyle, cullInk, cullTransform);
  617.             }
  618.         }
  619.     else 
  620.         {
  621.         gxRectangle    bounds;
  622.         
  623.         GXGetShapeLocalBounds(shape, &bounds);
  624.         
  625.         if (IsSomewhereInRectangle(pCullRect, &bounds))
  626.             {
  627.             if ( (shapeType == gxRectangleType) && (GXGetShapeTags(shape, gxQuickDrawPictTag, 1, gxSelectToEnd, nil) > 0) )
  628.                 {
  629.                 // convert shape and add -- but only if it goes okay
  630.                 GXSetShapeType(shape, gxPictureType);
  631.                 if (GXGetShapeType(shape) == gxPictureType)
  632.                     CullShape(shape, addToThis, pCullRect, cullStyle, cullInk, cullTransform);
  633.                 }
  634.             else
  635.                 {
  636.                 GXSetPictureParts(addToThis, 0, 0, 1, &shape, &cullStyle, &cullInk, &cullTransform);
  637.                 }
  638.             }
  639.         }
  640.         
  641. } // CullShape
  642.  
  643. // --------------------------------------------------------------------------------------------------------------
  644. static gxShape CullPicture(gxShape pictureShape, gxRectangle * pCullRect)
  645. /*
  646.     Returns a new shape that is all of the shapes inside of pictureShape
  647.     that intersect pCullRect.
  648. */
  649. {
  650.     gxShape        newPicture = GXNewShape(gxPictureType);
  651.     gxShape     clipShape = GXNewRectangle(pCullRect);
  652.     gxMapping    mapping;
  653.     gxRectangle    clipRect;
  654.     
  655.     // new shape as same mapping as old one
  656.     GXGetTransformMapping(GXGetShapeTransform(pictureShape), &mapping);
  657.     GXSetShapeMapping(newPicture, &mapping);
  658.     
  659.     // clip also has the mapping, but inverted so that it's the right space
  660.     InvertMapping(&mapping, &mapping);
  661.     GXMapShape(clipShape, &mapping);
  662.     GXGetShapeLocalBounds(clipShape, &clipRect);
  663.     
  664.     // clip to the selection
  665.     GXSetShapeClip(newPicture, clipShape);
  666.     GXDisposeShape(clipShape);
  667.  
  668.     // add all shapes that intersect the clip area
  669.     CullShape(pictureShape, newPicture, &clipRect, nil, nil, nil);
  670.         
  671.     // new shape is zero based
  672.     GXMoveShape(newPicture, -pCullRect->left, -pCullRect->top);
  673.     
  674.     return(newPicture);
  675.     
  676. } // CullPicture
  677.  
  678. // --------------------------------------------------------------------------------------------------------------
  679. static gxShape GetSelectedShape(WindowDataPtr pData)
  680. /*
  681.     Returns a shape that represents all shapes on the current page
  682.     that are contained by the current selection rectangle.
  683. */
  684. {
  685.     gxRectangle        cullRect;
  686.     gxShape            cullShape;
  687.     gxPoint            offset;
  688.     Fixed            zoomFactor = ((GXDataPtr)pData)->zoomFactor;
  689.     
  690.     // calculate the actual coodinate space, removing margins
  691.     {
  692.     gxRectangle        pageSize, paperSize;
  693.     
  694.     GetCurrentPageAndPaper(pData, &pageSize, &paperSize);
  695.     offset.y = FixedMultiply(-paperSize.top, zoomFactor);
  696.     offset.x = FixedMultiply(-paperSize.left, zoomFactor);
  697.     }
  698.     
  699.     // calculate the actual coodinates to copy
  700.     cullRect.top    = FixedDivide(ff(((GXDataPtr)pData)->selectionRectangle.top) - offset.y, zoomFactor);
  701.     cullRect.left    = FixedDivide(ff(((GXDataPtr)pData)->selectionRectangle.left) - offset.x, zoomFactor);
  702.     cullRect.bottom    = FixedDivide(ff(((GXDataPtr)pData)->selectionRectangle.bottom) - offset.y, zoomFactor);
  703.     cullRect.right    = FixedDivide(ff(((GXDataPtr)pData)->selectionRectangle.right) - offset.x, zoomFactor);
  704.     
  705.     // chop the data
  706.     cullShape = CullPicture(((GXDataPtr)pData)->currentPageShape, &cullRect);
  707.     
  708.     return(cullShape);
  709.     
  710. } // GetSelectedShape
  711.  
  712. // --------------------------------------------------------------------------------------------------------------
  713. static pascal OSErr GXSendDataProc(FlavorType theType, void *dragSendRefCon,
  714.                                 ItemReference theItem, DragReference theDrag)
  715. /*
  716.  *    The ItemReference is the gxShape to be sent. The dragSendRefCon is ignored.
  717. */
  718. {
  719. #pragma unused (dragSendRefCon)
  720.  
  721.     OSErr    result = noErr;
  722.     gxShape    shape = ((GXDataPtr)theItem)->tempDragShape;
  723.     
  724.     // haven't made clipped version yet?
  725.     if (shape == nil)
  726.         {
  727.         shape = GetSelectedShape((WindowDataPtr) theItem);
  728.         ((GXDataPtr)theItem)->tempDragShape = shape;
  729.         }
  730.         
  731.     switch (theType) 
  732.         {
  733.         case 'qdgx':
  734.             {    
  735.             Handle         flat;
  736.               userSpool     block;
  737.  
  738.             block.spool.spoolProcedure = gHandleSpoolProc;
  739.             block.spool.buffer = nil;
  740.             block.spool.bufferSize = 0;
  741.             GXFlattenShape(shape, gxFontListFlatten | gxFontGlyphsFlatten | gxFontVariationsFlatten, &block.spool);
  742.             flat = (Handle) block.data;
  743.     
  744.             if (flat)
  745.                 {    
  746.                 HLock(flat);
  747.                 result = SetDragItemFlavorData(theDrag, theItem, 'qdgx', *flat, GetHandleSize(flat), 0);
  748.                 DisposeHandle(flat);
  749.                 }
  750.             }
  751.             break;
  752.             
  753.         case 'PICT':
  754.             {    
  755.             PicHandle proxie = ShapeToPICT(shape);
  756.             PicHandle pict = DecompressShape(shape, proxie, false, true);
  757.     
  758.             if (proxie)
  759.                 KillPicture(proxie);
  760.             if (pict)
  761.                 {    
  762.                 HLock((Handle)pict);
  763.                 result = SetDragItemFlavorData(theDrag, theItem, 'PICT', (Ptr)*pict, GetHandleSize((Handle)pict), 0);
  764.                 KillPicture(pict);
  765.                 }
  766.             }
  767.             break;
  768.             
  769.         default:
  770.             result = badDragFlavorErr;
  771.             break;
  772.         }
  773.             
  774.     return result;
  775.     
  776. } // GXSendDataProc
  777.  
  778. #if GENERATINGCFM
  779.     static RoutineDescriptor gGXSendDataProcRD = BUILD_ROUTINE_DESCRIPTOR(uppDragSendDataProcInfo, GXSendDataProc);
  780.     static DragSendDataUPP gGXSendDataProc = &gGXSendDataProcRD;
  781. #else
  782.     static DragSendDataUPP gGXSendDataProc = NewDragSendDataProc(GXSendDataProc);
  783. #endif
  784.  
  785. // --------------------------------------------------------------------------------------------------------------
  786. static void ClearCurrentSelection(GXDataPtr pData)
  787. {
  788.     pData->currentShapeIndex = 0;
  789.     pData->currentShapeStart = 0;
  790.     pData->currentShapeEnd = 0;
  791.     if (pData->currentSelectionShape)
  792.         {
  793.         GXDisposeShape(pData->currentSelectionShape);
  794.         pData->currentSelectionShape = nil;
  795.         }
  796.         
  797. } // ClearCurrentSelection
  798.  
  799. // --------------------------------------------------------------------------------------------------------------
  800. static OSErr    GetCurrentPage(GXDataPtr pData, Boolean disposeOfSelection)
  801. /*
  802.     Disposes of previously loaded page information, and loads the
  803.     page information for the current page number.
  804. */
  805. {
  806.     OSErr        anErr;
  807.     LongRect    oldRect, newRect;
  808.     
  809.     if (pData->numberOfPages != 0)
  810.         {
  811.         // get rid of any previous format
  812.         if (pData->currentPageFormat)
  813.             {
  814.             GXDisposeFormat(pData->currentPageFormat);
  815.             pData->currentPageFormat = nil;
  816.             }
  817.             
  818.         // get rid of any previous shape
  819.         if (pData->currentPageShape)
  820.             {
  821.             GXDisposeShape(pData->currentPageShape);
  822.             pData->currentPageShape = nil;
  823.             }
  824.             
  825.         // get rid of selection, if desired
  826.         if (disposeOfSelection)
  827.             ClearCurrentSelection(pData);
  828.  
  829.         GXGetDocumentRect((WindowRef)pData, (WindowDataPtr)pData, &oldRect, false);
  830.         
  831.         GXReadPrintFilePage(pData->thePrintFile, 
  832.             pData->currentPage, 
  833.             1, &pData->childViewPort, 
  834.             &pData->currentPageFormat, &pData->currentPageShape);
  835.         }
  836.         
  837.     anErr = GXGetJobError(pData->w.hPrint);
  838.     
  839.     if (anErr == noErr)
  840.         {
  841.         GXGetDocumentRect((WindowRef)pData,(WindowDataPtr) pData, &newRect, false);
  842.         
  843.         if     (
  844.             (oldRect.left != newRect.left) ||
  845.             (oldRect.top != newRect.top) ||
  846.             (oldRect.right != newRect.right) ||
  847.             (oldRect.bottom != newRect.bottom)
  848.             )
  849.             {
  850.             // if the resulting page is < the current window size, we need to resize,
  851.             long newWidth     = newRect.right - newRect.left + kScrollBarSize;
  852.             long newHeight     = newRect.bottom - newRect.top + kScrollBarSize;
  853.             long oldWidth     = pData->w.theWindow.port.portRect.right - pData->w.theWindow.port.portRect.left;
  854.             long oldHeight     = pData->w.theWindow.port.portRect.bottom - pData->w.theWindow.port.portRect.top;
  855.             
  856.             // but don't let it get too small!
  857.             if (newWidth < pData->w.minHSize)
  858.                 newWidth = pData->w.minHSize;
  859.             if (newHeight < kMinGXDocSize)
  860.                 newHeight = kMinGXDocSize;
  861.                 
  862.             if     (
  863.                 (newWidth < oldWidth) ||
  864.                 (newHeight < oldHeight)
  865.                 )
  866.                 {
  867.                 if (newWidth > oldWidth)
  868.                     newWidth = oldWidth;
  869.                 if (newHeight > oldHeight)
  870.                     newHeight = oldHeight;
  871.                     
  872.                 SizeWindow((WindowRef)pData, newWidth, newHeight, false);
  873.                 }
  874.                 
  875.             // and in any case, the scroll bars should update
  876.             AdjustScrollBars((WindowRef)pData, true, true, nil);
  877.             }
  878.         }
  879.         
  880.     return(anErr);
  881.     
  882. } // GetCurrentPage
  883.  
  884. // --------------------------------------------------------------------------------------------------------------
  885. #define charBullet    '•'
  886.  
  887. static void GetIntlTokenChar(short whichToken, short whichScript, char *bulletString)
  888. //
  889. // GetIntlTokenChar
  890. //
  891. // This routine gets a character out of the itl4 given a script and token…
  892. //
  893. {
  894.     Handle    itl4H;
  895.     long    offset, len;
  896.  
  897.     // default the value
  898.     bulletString[0] = 1;
  899.     bulletString[1] = charBullet;
  900.     
  901.     // Look up the untoken table -- bail if we can’t get it
  902.     GetIntlResourceTable(whichScript, iuUnTokenTable, &itl4H, &offset, &len);
  903.     if (itl4H && (offset > 0) && (len >= 0))
  904.     {
  905.         char *sp = (*itl4H + offset);                // Point to start of untoken table
  906.         if (whichToken <= ((short *)sp)[1])            // Check if token has valid index
  907.         {
  908.             sp += ((short *)sp)[2+whichToken];        // Add the string offset and voliá!
  909.             BlockMoveData(sp, bulletString, sp[0]+1);
  910.         }
  911.     }
  912.     
  913. } // GetIntlTokenChar
  914.  
  915. // --------------------------------------------------------------------------------------------------------------
  916. // This code is required to change pop up menus to a different font size.  It would be
  917. // better to use the pop up control, but it doesn't allow multiple items to be marked.
  918.  
  919. #define SysFontSize    0xBA8
  920. #define SysFontFam    0xBA6
  921. #define CurFMInput    0x988
  922.  
  923. static void DoUseWFont(TextState *savedInfo, WindowRef owner,  Boolean saveIt)
  924. /*************************************************************
  925.     DoUseWFont        - Sets the font mgr low mem globals so
  926.                         we can have Geneva 9 popups
  927.  
  928.         savedInfo    - Fills it in if saveIt = true, else
  929.                         it sets the port to those values
  930.         owner        - Where to get the original values
  931.         saveIt        - true for save
  932. **************************************************************/
  933. {
  934.     TextState        myState,
  935.                     *theState;
  936.     short            aFont;
  937.  
  938.     theState = savedInfo;
  939.  
  940.     if (saveIt) 
  941.         {
  942.         savedInfo->theFont = GetSysFont();    // save low memory globals
  943.         savedInfo->theSize = *((short *) SysFontSize);
  944.  
  945.         myState.theFont = GetWindowPort(owner)->txFont;
  946.         myState.theSize = GetWindowPort(owner)->txSize;
  947.         theState = &myState;
  948.  
  949.         // if we stuff systemFont, it will screw up Script Mgr
  950.         if (GetWindowPort(owner)->txFont == systemFont)
  951.             goto dosizestuff;
  952.         }
  953.  
  954.     // if we stuff applFont, this will also screw up Script Mgr
  955.     // instead we get the actual font
  956.     aFont = theState->theFont;
  957.     if (saveIt)
  958.         if (GetWindowPort(owner)->txFont == applFont)
  959.             aFont = GetAppFont();
  960.     *((short *) SysFontFam) = aFont;                    // set/restore low memory globals
  961.  
  962. dosizestuff:
  963.     *((short *) SysFontSize) = theState->theSize;
  964.  
  965.     *((long *) CurFMInput) = 0xFFFFFFFF;
  966.     
  967. } // DoUseWFont
  968.  
  969.  
  970. // --------------------------------------------------------------------------------------------------------------
  971.  
  972. static void SetZoom(WindowRef pWindow, WindowDataPtr pData, Fixed newZoom)
  973. /*
  974.     Sets the new zoom factor for the window, causing an update for
  975.     the window if required.
  976. */
  977. {
  978.     Fixed    scaleFactor;
  979.     
  980.     // pin to max/min zoom factors
  981.     if (newZoom > ff(32))
  982.         newZoom = ff(32);
  983.     if (newZoom < 0x0800)
  984.         newZoom = 0x0800;
  985.     
  986.     scaleFactor = FixedDivide(newZoom, ((GXDataPtr)pData)->zoomFactor);
  987.     
  988.     if (scaleFactor != ff(1))
  989.         {
  990.         gxPoint        centerPoint;
  991.         GrafPtr        pPort = (GrafPtr)GetWindowPort(pWindow);
  992.         
  993.         // zoom about the window center
  994.         centerPoint.x = ff(pPort->portRect.left + (RectWidth(pPort->portRect) >> 1));
  995.         centerPoint.y = ff(pPort->portRect.top + (RectHeight(pPort->portRect) >> 1));
  996.         
  997.         // new zoom active
  998.         ((GXDataPtr)pData)->zoomFactor = newZoom;
  999.         
  1000.         // force update and recalc the size of window
  1001.         InvalRect(&pPort->portRect);
  1002.         AdjustScrollBars(pWindow, true, true, nil);
  1003.  
  1004.          // scale scroll values
  1005.         SetControlValue(pData->hScroll, FixedToInt( FixedDivide(centerPoint.x, scaleFactor) + FixedMultiply(ff(GetControlValue(pData->hScroll)), scaleFactor) ) );
  1006.         SetControlValue(pData->vScroll, FixedToInt( FixedDivide(centerPoint.y, scaleFactor) + FixedMultiply(ff(GetControlValue(pData->vScroll)), scaleFactor) ) );
  1007.         
  1008.         // zoom the selection
  1009.         ((GXDataPtr)pData)->selectionRectangle.left     = FixedToInt (FixedMultiply(ff(((GXDataPtr)pData)->selectionRectangle.left), scaleFactor) );
  1010.         ((GXDataPtr)pData)->selectionRectangle.top         = FixedToInt (FixedMultiply(ff(((GXDataPtr)pData)->selectionRectangle.top), scaleFactor) );
  1011.         ((GXDataPtr)pData)->selectionRectangle.right     = FixedToInt (FixedMultiply(ff(((GXDataPtr)pData)->selectionRectangle.right), scaleFactor) );
  1012.         ((GXDataPtr)pData)->selectionRectangle.bottom     = FixedToInt (FixedMultiply(ff(((GXDataPtr)pData)->selectionRectangle.bottom), scaleFactor) );
  1013.         }
  1014.     
  1015. } // SetZoom
  1016.  
  1017. // --------------------------------------------------------------------------------------------------------------
  1018.  
  1019. static void SetShapeGreyColorLevel(gxShape thisShape, unsigned long greyLevel)
  1020. {
  1021.     gxColor thisColor;
  1022.  
  1023.     thisColor.space = gxGraySpace;
  1024.     thisColor.profile = nil;
  1025.     thisColor.element.gray = greyLevel;
  1026.     GXSetShapeColor(thisShape, &thisColor);
  1027.     
  1028. } // SetShapeGreyColorLevel
  1029.  
  1030. // --------------------------------------------------------------------------------------------------------------
  1031. static void    CenterRect(Rect *source, Rect *against)
  1032. /*
  1033.     Centers "source" within or around "against".
  1034. */
  1035. {
  1036.     // center picture if requested
  1037.     short    height, width, pheight, pwidth;
  1038.     
  1039.     height = (against->bottom - against->top) >> 1;
  1040.     width = (against->right - against->left) >> 1;
  1041.     pheight = (source->bottom - source->top) >> 1;
  1042.     pwidth = (source->right - source->left) >> 1;
  1043.     
  1044.     source->top = against->top + height - pheight;
  1045.     source->bottom = against->bottom - height + pheight;
  1046.     source->left = against->left + width - pwidth;
  1047.     source->right = against->right - width + pwidth;
  1048.  
  1049. } // CenterRect
  1050.  
  1051. // --------------------------------------------------------------------------------------------------------------
  1052.  
  1053. static gxShape FindNestedIndexedLayout(gxShape shape, 
  1054.                     long searchIndex, long * pIndex, gxMapping *pConcatMapping)
  1055. /*
  1056.     Returns the shape represented by "searchIndex" shapes into the picture,
  1057.     sequentially, including all nestings of pictures.  Uses pIndex as
  1058.     work storage, which must be initialized to zero before the call.
  1059.     
  1060.     Returns shape found, or NIL if the searchIndex is larger than
  1061.     the number of shapes in the picture.  If NIL is returned,
  1062.     then the contents of pIndex will contain the number of
  1063.     shapes in the picture.
  1064. */
  1065. {
  1066.     gxShape        returnShape = nil;
  1067.     gxShapeType shapeType = GXGetShapeType(shape);
  1068.  
  1069.     // bail on negative index
  1070.     if (searchIndex < 0)
  1071.         return(nil);
  1072.         
  1073.     if (shapeType == gxPictureType)
  1074.         {    
  1075.         long        index, count;
  1076.         gxShape        contentShape;
  1077.         gxTransform    contentTransform;
  1078.         gxMapping    contentMapping;
  1079.         
  1080.         count = GXGetPicture(shape, nil, nil, nil, nil);
  1081.         for (index = 0; index < count; index++)
  1082.             {
  1083.             GXGetPictureParts(shape, index+1, 1, &contentShape, nil, nil, &contentTransform);
  1084.             
  1085.             returnShape = FindNestedIndexedLayout(contentShape, searchIndex, pIndex, pConcatMapping ? &contentMapping : nil);
  1086.             if (returnShape)
  1087.                 {
  1088.                 if (pConcatMapping)
  1089.                     {
  1090.                     if (!contentTransform)
  1091.                         contentTransform = GXGetShapeTransform(contentShape);
  1092.                     GXGetTransformMapping(contentTransform, &contentMapping);
  1093.                     MapMapping(&contentMapping, pConcatMapping);
  1094.                     *pConcatMapping = contentMapping;
  1095.                     }
  1096.                 break;
  1097.                 }
  1098.             }
  1099.         }
  1100.     else 
  1101.         {
  1102.         if ( (shapeType == gxLayoutType) || (shapeType == gxGlyphType) || (shapeType == gxTextType) )
  1103.             {
  1104.             (*pIndex)++;
  1105.             if (searchIndex == *pIndex)
  1106.                 returnShape = shape;
  1107.             }
  1108.         }
  1109.         
  1110.     return(returnShape);
  1111.     
  1112. } // FindNestedIndexedLayout
  1113.  
  1114. // --------------------------------------------------------------------------------------------------------------
  1115. static Boolean PerformNextFind(WindowRef pWindow, WindowDataPtr pData,
  1116.                 Str255 findString,
  1117.                 Boolean caseSensitive,
  1118.                 Boolean backwards,
  1119.                 Boolean wraparound)
  1120. {
  1121.     Boolean    foundSomething = false;
  1122.     long    searchIndex, workIndex;
  1123.     gxShape    aShape;
  1124.     long    direction;
  1125.     long    oldPageNumber = ((GXDataPtr)pData)->currentPage;
  1126.     long    endPageNumber;
  1127.     Boolean    firstTime = true;
  1128.     gxMapping    concatMapping;
  1129.     
  1130.     // initialize direction of the walk
  1131.     if (backwards)
  1132.         direction = -1;
  1133.     else
  1134.         direction = 1;
  1135.     
  1136.     // start searching where we last left off    
  1137.     searchIndex = ((GXDataPtr)pData)->currentShapeIndex;
  1138.     if (searchIndex != 0)
  1139.         searchIndex -= direction;
  1140.     
  1141.     if (((GXDataPtr)pData)->numberOfPages == 1)
  1142.         wraparound = false;
  1143.  
  1144.     // end searching on a particular page
  1145.     if (backwards)
  1146.         endPageNumber = 0;
  1147.     else
  1148.         endPageNumber = ((GXDataPtr)pData)->numberOfPages + 1;
  1149.     
  1150.     // can't search on qd shapes, so we get rid of them
  1151.     GetRidOfAnyQDShapeTags(((GXDataPtr)pData)->currentPageShape);
  1152.  
  1153.     do
  1154.         {
  1155.         // search for the next shape or prev shape
  1156.         searchIndex += direction;
  1157.         
  1158.         // initialize the working index so that we know traversal level
  1159.         workIndex = 0;
  1160.         
  1161.         // initialize the mapping to identity
  1162.         ResetMapping(&concatMapping);
  1163.         GXGetShapeMapping(((GXDataPtr)pData)->currentPageShape, &concatMapping);
  1164.         
  1165.         // find the next layout in the page
  1166.         aShape = FindNestedIndexedLayout(((GXDataPtr)pData)->currentPageShape, searchIndex, &workIndex, &concatMapping);
  1167.         if (aShape)
  1168.             {
  1169.             gxShapeType shapeType = GXGetShapeType(aShape);
  1170.             long          size;
  1171.             Handle        aHandle;
  1172.             
  1173.             // determine size and allocate storage for layout contents
  1174.             switch (shapeType)
  1175.                 {
  1176.                 case gxTextType:
  1177.                     size = GXGetText(aShape, nil, nil, nil);
  1178.                     break;
  1179.                 case gxGlyphType:
  1180.                     size = GXGetGlyphs(aShape, nil, nil, nil,
  1181.                                     nil, nil, nil, nil, nil);
  1182.                     break;
  1183.                 case gxLayoutType:
  1184.                     size = GXGetLayout(aShape, nil,
  1185.                                     nil, nil, nil,     // styles
  1186.                                     nil, nil, nil,     // levels
  1187.                                     nil, nil);        // options/position
  1188.                     break;
  1189.                 }
  1190.             aHandle = NewHandle(size);
  1191.             
  1192.             if (aHandle)
  1193.                 {
  1194.                 long newStart, newEnd;
  1195.                 
  1196.                 // grab the contents of the layout into the temp storage
  1197.                 HLock(aHandle);
  1198.                 switch (shapeType)
  1199.                     {
  1200.                     case gxTextType:
  1201.                         GXGetText(aShape, nil, (unsigned char*)*aHandle, nil);
  1202.                         break;
  1203.                     case gxGlyphType:
  1204.                         GXGetGlyphs(aShape, nil,  (unsigned char*)*aHandle, nil,
  1205.                                         nil, nil, nil, nil, nil);
  1206.                         break;
  1207.                     case gxLayoutType:
  1208.                         GXGetLayout(aShape,  (unsigned char*)*aHandle,
  1209.                                     nil, nil, nil,     // styles
  1210.                                     nil, nil, nil,     // levels
  1211.                                     nil, nil);        // options/position
  1212.                         break;
  1213.                     }
  1214.                 HUnlock(aHandle);
  1215.                 
  1216.                 // search the handle for the string we're looking for,
  1217.                 // but don't wraparound because we handle that over layout
  1218.                 // ranges and pages ourselves
  1219.                 {
  1220.                 long offset;
  1221.                 
  1222.                 if ((firstTime) && (((GXDataPtr)pData)->currentSelectionShape))
  1223.                     {
  1224.                     // for shape that we have found something in before
  1225.                     // start at end of last point if forwards, start of last point
  1226.                     // if backwards
  1227.                     firstTime = false;
  1228.                     offset = backwards ? ((GXDataPtr)pData)->currentShapeStart : ((GXDataPtr)pData)->currentShapeEnd;
  1229.                     }
  1230.                 else
  1231.                     {
  1232.                     // for "new" shape we haven't hit before, start at
  1233.                     // begining for forwards, end for backwards
  1234.                     offset = backwards ? size : 0;
  1235.                     }
  1236.                     
  1237.                 foundSomething = PerformSearch(aHandle, offset, findString, 
  1238.                             caseSensitive, backwards, false,
  1239.                             &newStart, &newEnd);
  1240.                 }
  1241.                             
  1242.                 // done with our temp storage
  1243.                 DisposeHandle(aHandle);
  1244.                 
  1245.                 // got it?  then mark it and bail out
  1246.                 if (foundSomething)
  1247.                     {
  1248.                     // remember where we are in the page
  1249.                     ((GXDataPtr)pData)->currentShapeIndex = searchIndex;
  1250.                     
  1251.                     // what offsets the selection is
  1252.                     ((GXDataPtr)pData)->currentShapeStart = newStart;
  1253.                     ((GXDataPtr)pData)->currentShapeEnd = newEnd;
  1254.                     
  1255.                     // and the shape containing the selection
  1256.                     if (((GXDataPtr)pData)->currentSelectionShape)
  1257.                         GXDisposeShape(((GXDataPtr)pData)->currentSelectionShape);
  1258.                     ((GXDataPtr)pData)->currentSelectionShape = GXCloneShape(aShape);
  1259.                     ((GXDataPtr)pData)->currentSelectionMapping = concatMapping;
  1260.                     break;
  1261.                     } // found the string
  1262.                     
  1263.                 } // allocated the handle
  1264.                 
  1265.             } // found a shape
  1266.         else
  1267.             {
  1268.             OSErr    anErr = noErr;
  1269.             
  1270.             // didn't find it on this page, move on
  1271.             ((GXDataPtr)pData)->currentPage += direction;
  1272.             
  1273.                 
  1274.             // clamp to the ends of the range
  1275.             if (backwards)
  1276.                 {
  1277.                 if (((GXDataPtr)pData)->currentPage <= endPageNumber)
  1278.                     {
  1279.                     if (wraparound)
  1280.                         {
  1281.                         ((GXDataPtr)pData)->currentPage = ((GXDataPtr)pData)->numberOfPages;
  1282.                         endPageNumber = oldPageNumber;
  1283.                         wraparound = false;
  1284.                         }
  1285.                     else
  1286.                         anErr = paramErr;
  1287.                     }
  1288.                 }
  1289.             else
  1290.                 {
  1291.                 if (((GXDataPtr)pData)->currentPage >= endPageNumber)
  1292.                     {
  1293.                     if (wraparound)
  1294.                         {
  1295.                         ((GXDataPtr)pData)->currentPage = 1;
  1296.                         endPageNumber = oldPageNumber;
  1297.                         wraparound = false;
  1298.                         }
  1299.                     else
  1300.                         anErr = paramErr;
  1301.                     }
  1302.                 }
  1303.                 
  1304.             // fetch contents
  1305.             if (anErr == noErr)
  1306.                 anErr = GetCurrentPage((GXDataPtr) pData, false);
  1307.                 
  1308.             // anything wrong?  then all done searching
  1309.             if (anErr != noErr)
  1310.                 {
  1311.                 break;
  1312.                 }
  1313.             else
  1314.                 {
  1315.                 GetRidOfAnyQDShapeTags(((GXDataPtr)pData)->currentPageShape);
  1316.                 if (backwards)
  1317.                     {
  1318.                     workIndex = 0;
  1319.                     (void) FindNestedIndexedLayout(((GXDataPtr)pData)->currentPageShape, 0x7FFFFFF, &workIndex, nil);
  1320.                     searchIndex = workIndex;
  1321.                     }
  1322.                 else
  1323.                     searchIndex = 0;
  1324.                 }
  1325.             }
  1326.         } while (!foundSomething);
  1327.     
  1328.     // if we found something, force and update.  If not, make sure
  1329.     // that the current page is restored to the page we had when 
  1330.     // coming in.
  1331.     if (foundSomething)
  1332.         {
  1333.         InvalRect(&GetWindowPort(pWindow)->portRect);
  1334.         }
  1335.     else
  1336.         {
  1337.         if (oldPageNumber != ((GXDataPtr)pData)->currentPage)
  1338.             {
  1339.             ((GXDataPtr)pData)->currentPage = oldPageNumber;
  1340.             GetCurrentPage((GXDataPtr) pData, false);
  1341.             }
  1342.         }
  1343.     return(foundSomething);
  1344.     
  1345. } // PerformNextFind
  1346.  
  1347. // --------------------------------------------------------------------------------------------------------------
  1348. static gxShape GetCurrentSelectionHighlight(WindowDataPtr pData, Boolean mapIt)
  1349. {
  1350.     gxShape        highlight;
  1351.     
  1352.     highlight = GXGetLayoutHighlight(((GXDataPtr)pData)->currentSelectionShape, 
  1353.                         ((GXDataPtr)pData)->currentShapeStart, ((GXDataPtr)pData)->currentShapeEnd,
  1354.                         gxHighlightAverageAngle, nil);
  1355.                         
  1356.     
  1357.     if (mapIt)
  1358.         GXMapShape(highlight, &((GXDataPtr)pData)->currentSelectionMapping);
  1359.     
  1360.     // draw and dispose of the highlight
  1361.     GXSetShapeViewPorts(highlight, 1, &((GXDataPtr)pData)->childViewPort);
  1362.     GXSetShapeFill(highlight, gxClosedFrameFill);
  1363.     GXSetShapeClip(highlight, nil);
  1364.  
  1365.     return(highlight);
  1366.     
  1367. } // GetCurrentSelectionHighlight
  1368.  
  1369. // --------------------------------------------------------------------------------------------------------------
  1370. static void ScrollFoundShapeIntoView(WindowRef pWindow, WindowDataPtr pData)
  1371. {
  1372.     gxRectangle    bounds;
  1373.     Point        scrollAmount;
  1374.     Point        controlValues;
  1375.     gxRectangle    windowBounds;
  1376.     GrafPtr        pPort = (GrafPtr)GetWindowPort(pWindow);
  1377.     
  1378.     if ( ! (((GXDataPtr)pData)->currentSelectionShape) )
  1379.         return;
  1380.         
  1381.     // cache scroll state
  1382.     controlValues.h = GetControlValue(pData->hScroll);
  1383.     controlValues.v = GetControlValue(pData->vScroll);
  1384.     
  1385.     // calculate visible bounds of window
  1386.     windowBounds.left         = ff(pPort->portRect.left + controlValues.h);
  1387.     windowBounds.right         = ff(pPort->portRect.right - kScrollBarSize + controlValues.h);
  1388.     windowBounds.top         = ff(pPort->portRect.top + controlValues.v);
  1389.     windowBounds.bottom     = ff(pPort->portRect.bottom - kScrollBarSize + controlValues.v);                
  1390.  
  1391.     // grab the bounds of the shape, add on the margins, scale to zoom factor
  1392.     {
  1393.     gxRectangle        pageSize, paperSize;
  1394.     gxShape            highlight = GetCurrentSelectionHighlight(pData, false);
  1395.     
  1396.     GXGetShapeBounds(highlight, 0, &bounds);
  1397.     GXDisposeShape(highlight);
  1398.     GetCurrentPageAndPaper(pData, &pageSize, &paperSize);
  1399.     bounds.left     = FixedMultiply(bounds.left - paperSize.left, ((GXDataPtr)pData)->zoomFactor);
  1400.     bounds.right     = FixedMultiply(bounds.right - paperSize.left, ((GXDataPtr)pData)->zoomFactor);
  1401.     bounds.top         = FixedMultiply(bounds.top - paperSize.top, ((GXDataPtr)pData)->zoomFactor);
  1402.     bounds.bottom     = FixedMultiply(bounds.bottom - paperSize.top, ((GXDataPtr)pData)->zoomFactor);
  1403.     }
  1404.  
  1405.     if     (
  1406.         (bounds.bottom <= windowBounds.top) ||
  1407.         (bounds.top >= windowBounds.bottom) ||
  1408.         (bounds.right <= windowBounds.left) ||
  1409.         (bounds.left >= windowBounds.right) 
  1410.         )
  1411.         {
  1412.         scrollAmount.h = controlValues.h - FixedToInt(bounds.left);
  1413.         scrollAmount.v = controlValues.v - FixedToInt(bounds.top);
  1414.         
  1415.         SetControlAndClipAmount(pData->hScroll, &scrollAmount.h);
  1416.         SetControlAndClipAmount(pData->vScroll, &scrollAmount.v);
  1417.         if ((scrollAmount.h) || (scrollAmount.v))
  1418.             DoScrollContent(pWindow, pData, scrollAmount.h, scrollAmount.v);
  1419.         }
  1420.         
  1421. } // ScrollFoundShapeIntoView
  1422.  
  1423. // --------------------------------------------------------------------------------------------------------------
  1424. static Boolean TrackIn(Rect *pTrackRect, Point clickPoint, Rect *pDrawRect, short inID, short outID)
  1425. {
  1426.     Boolean    in = false;
  1427.     
  1428.     if (PtInRect(clickPoint, pTrackRect))
  1429.         {
  1430.         in = true;
  1431.         
  1432.         PlotIconID(pDrawRect, ttNone, ttNone, inID);
  1433.         while (StillDown())
  1434.             {
  1435.             GetMouse(&clickPoint);
  1436.             
  1437.             if (PtInRect(clickPoint, pTrackRect))
  1438.                 {
  1439.                 if (!in)
  1440.                     {
  1441.                     in = true;
  1442.                     PlotIconID(pDrawRect, ttNone, ttNone, inID);
  1443.                     }
  1444.                 }
  1445.             else
  1446.                 {
  1447.                 if (in)
  1448.                     {
  1449.                     in = false;
  1450.                     PlotIconID(pDrawRect, ttNone, ttNone, outID);
  1451.                     }
  1452.                 }
  1453.             }
  1454.         }
  1455.         
  1456.     return(in);
  1457.     
  1458. } // TrackIn
  1459.  
  1460. // --------------------------------------------------------------------------------------------------------------
  1461. static void DrawPageSliderAndThumb(WindowRef pWindow, long currentValue, long maxValue)
  1462. {
  1463.     Rect        pageSliderRect;
  1464.     Rect        pageThumbRect;
  1465.     long        pixelValue;
  1466.     Str255        aString;
  1467.     FontInfo    theInfo;
  1468.     PicHandle    proxyHandle;
  1469.     Rect        proxyRect;
  1470.     GrafPtr        pPort = (GrafPtr)GetWindowPort(pWindow);
  1471.     
  1472.     // calculate location of the slider
  1473.     pageSliderRect.left     = kPageSliderMargins;
  1474.     pageSliderRect.bottom     = pPort->portRect.bottom - kPageSliderMargins;
  1475.     pageSliderRect.top         = pageSliderRect.bottom - kPageSliderHeight;
  1476.     pageSliderRect.right     = pPort->portRect.right - kPageSliderMargins;
  1477.         
  1478.     // then calculate the thumb within that slider
  1479.     pixelValue = (currentValue-1) 
  1480.                 *
  1481.                 (pageSliderRect.right - pageSliderRect.left - kPageThumbMargins*2 - kPageThumbWidth) 
  1482.                 /
  1483.                 (maxValue-1);
  1484.                 
  1485.     pageThumbRect.left         = pageSliderRect.left + kPageThumbMargins + pixelValue;
  1486.     pageThumbRect.right        = pageThumbRect.left + kPageThumbWidth;
  1487.     pageThumbRect.top        = pageSliderRect.top - kPageThumbEdge;
  1488.     pageThumbRect.bottom    = pageThumbRect.top + kPageThumbHeight;
  1489.  
  1490.     // and finally, the location to draw the proxy (if any)
  1491.     proxyRect.top            = kPageSliderMargins;
  1492.     proxyRect.bottom        = proxyRect.top + kProxyHeight;
  1493.     proxyRect.left            = pPort->portRect.left + 
  1494.                                 ((pPort->portRect.right - pPort->portRect.left) >> 1) -
  1495.                                 (kProxyWidth >> 1);
  1496.     proxyRect.right            = proxyRect.left + kProxyWidth;
  1497.     if (Count1Resources(kProxyType) == 0)
  1498.         proxyRect.bottom = proxyRect.top;
  1499.         
  1500.     // draw the slider area
  1501.     FillRect(&pageSliderRect, &qd.gray);
  1502.     FrameRect(&pageSliderRect);
  1503.  
  1504.     // erase areas above and below the slider (old thumb erase)
  1505.     {
  1506.     Rect    sliderEraseRect = pageSliderRect;
  1507.     
  1508.     ForeColor(whiteColor);
  1509.     sliderEraseRect.top = pageThumbRect.top;
  1510.     sliderEraseRect.bottom = sliderEraseRect.top + kPageThumbEdge;
  1511.     PaintRect(&sliderEraseRect);
  1512.     sliderEraseRect.bottom = pageThumbRect.bottom;
  1513.     sliderEraseRect.top = sliderEraseRect.bottom - kPageThumbEdge;
  1514.     PaintRect(&sliderEraseRect);
  1515.     }
  1516.     
  1517.     // draw the thumb
  1518.     ForeColor(blackColor);
  1519.     FrameRect(&pageThumbRect);
  1520.     InsetRect(&pageThumbRect, 1, 1);
  1521.     ForeColor(whiteColor);
  1522.     FrameRect(&pageThumbRect);
  1523.     InsetRect(&pageThumbRect, 1, 1);
  1524.     ForeColor(blackColor);
  1525.     FrameRect(&pageThumbRect);
  1526.  
  1527.     // draw page string label
  1528.     TextFace(bold);
  1529.     TextFont(applFont);
  1530.     TextSize(9);
  1531.     TextMode(srcCopy);
  1532.     GetFontInfo(&theInfo);
  1533.     
  1534.     MoveTo(pageSliderRect.left, pageThumbRect.top - kPageThumbEdge - theInfo.descent);
  1535.     GetIndString(aString, kPageControlStrings, iGoToPageString);
  1536.     DrawString(aString);
  1537.     NumToString(currentValue, aString);
  1538.     DrawString(aString);
  1539.     
  1540.     // erase any trailing digits (pretty cheezy, but seems to work)
  1541.     DrawString("\p       ");
  1542.     
  1543.     // draw the proxy, or erase the proxy area if no picture to draw
  1544.     proxyHandle = (PicHandle) GetResource(kProxyType, kProxyBaseID + currentValue - 1);
  1545.     if (proxyHandle)
  1546.         {
  1547.         Rect    drawRect;
  1548.         Fixed    scaleFactor;
  1549.         
  1550.         drawRect = (**proxyHandle).picFrame;
  1551.         
  1552.         // compute aspect ratio preserving scale
  1553.         if (RectHeight(drawRect) > RectWidth(drawRect))
  1554.             scaleFactor = FixRatio(RectHeight(proxyRect), RectHeight(drawRect));
  1555.         else
  1556.             scaleFactor = FixRatio(RectWidth(proxyRect), RectWidth(drawRect));
  1557.         drawRect.bottom = drawRect.top +
  1558.                     ( FixMul( (RectHeight(drawRect) << 16), scaleFactor) >> 16);
  1559.         drawRect.right = drawRect.left +
  1560.                     ( FixMul( (RectWidth(drawRect) << 16), scaleFactor) >> 16);
  1561.         CenterRect(&drawRect, &proxyRect);
  1562.         
  1563.         // erase the area outside of the picture, but inside of the 
  1564.         // total proxy area, because some pictures will leave whitespace on the edge
  1565.         {
  1566.         RgnHandle    rgn1 = NewRgn();
  1567.         RgnHandle    rgn2 = NewRgn();
  1568.         
  1569.         RectRgn(rgn1, &proxyRect);
  1570.         RectRgn(rgn2, &drawRect);
  1571.         DiffRgn(rgn1, rgn2, rgn1);
  1572.         EraseRgn(rgn1);
  1573.         DisposeRgn(rgn1);
  1574.         DisposeRgn(rgn2);
  1575.         }
  1576.  
  1577.         // finally, we can draw and dispose of the picture
  1578.         DrawPicture(proxyHandle, &drawRect);
  1579.         ReleaseResource((Handle) proxyHandle);
  1580.         
  1581.         }
  1582.     else
  1583.         {
  1584.         EraseRect(&proxyRect);
  1585.         }
  1586.         
  1587. } // DrawPageSliderAndThumb
  1588.  
  1589. // --------------------------------------------------------------------------------------------------------------
  1590. static OSErr    DoDrawingClick(WindowRef pWindow, WindowDataPtr pData, Point clickPoint, EventRecord *pEvent)
  1591. {
  1592. #pragma unused (pEvent, pWindow)
  1593.  
  1594.     OSErr    anErr = noErr;
  1595.     Point    lastPoint = clickPoint;
  1596.     Point    currentPoint;
  1597.     Fixed    penSize;
  1598.     gxInk    newInk = GXNewInk();
  1599.     gxStyle newStyle = GXNewStyle();
  1600.     gxShape    newShape = GXNewShape(gxPolygonType);
  1601.     long    addPoly[] = {1, 1, 0, 0};
  1602.     
  1603.     // set up the style for the shape
  1604.     GXSetStylePen(newStyle, ff(10));
  1605.     
  1606.     // and the ink for the shape
  1607.     {
  1608.     gxColor    redColor;
  1609.     gxTransferMode mode;
  1610.     
  1611.     // the color
  1612.     redColor.space        = gxRGBSpace;
  1613.     redColor.profile    = nil;
  1614.     redColor.element.rgb.red    = 0xFFFF;
  1615.     redColor.element.rgb.green    = 0x0000;
  1616.     redColor.element.rgb.blue    = 0x0000;
  1617.     GXSetInkColor(newInk, &redColor);
  1618.     
  1619.     // the transfer mode
  1620.     mode.space         = gxHSVSpace;
  1621.     mode.set        = nil;
  1622.     mode.profile    = nil;
  1623.     InitColorMatrix(mode.sourceMatrix);
  1624.     InitColorMatrix(mode.deviceMatrix);
  1625.     InitColorMatrix(mode.resultMatrix);
  1626.     mode.flags        = 0;
  1627.     
  1628.     mode.component[0].mode    = gxCopyMode;
  1629.     mode.component[0].flags    = 0;
  1630.     mode.component[0].sourceMinimum    = 0;
  1631.     mode.component[0].sourceMaximum    = gxColorValue1;
  1632.     mode.component[0].deviceMinimum    = 0;
  1633.     mode.component[0].deviceMaximum    = gxColorValue1;
  1634.     mode.component[0].clampMinimum    = 0;
  1635.     mode.component[0].clampMaximum    = gxColorValue1;
  1636.     mode.component[0].operand        = 0;
  1637.  
  1638.     mode.component[1].mode    = gxCopyMode;
  1639.     mode.component[1].flags    = 0;
  1640.     mode.component[1].sourceMinimum    = 0;
  1641.     mode.component[1].sourceMaximum    = gxColorValue1;
  1642.     mode.component[1].deviceMinimum    = 0;
  1643.     mode.component[1].deviceMaximum    = gxColorValue1;
  1644.     mode.component[1].clampMinimum    = 0;
  1645.     mode.component[1].clampMaximum    = gxColorValue1;
  1646.     mode.component[1].operand        = 0;
  1647.  
  1648.     mode.component[2].mode    = gxNoMode;
  1649.     mode.component[2].flags    = 0;
  1650.     mode.component[2].sourceMinimum    = 0;
  1651.     mode.component[2].sourceMaximum    = gxColorValue1;
  1652.     mode.component[2].deviceMinimum    = 0;
  1653.     mode.component[2].deviceMaximum    = gxColorValue1;
  1654.     mode.component[2].clampMinimum    = 0;
  1655.     mode.component[2].clampMaximum    = gxColorValue1;
  1656.     mode.component[2].operand        = 0;
  1657.     GXSetInkTransfer(newInk, &mode);
  1658.     }
  1659.     
  1660.     // set the style and ink of the shape
  1661.     GXSetShapeStyle(newShape, newStyle);
  1662.     GXSetShapeInk(newShape, newInk);
  1663.     GXSetShapeFill(newShape, gxOpenFrameFill);
  1664.     
  1665.     // initialize the first point in the shape
  1666.     addPoly[2] = ff(lastPoint.h);
  1667.     addPoly[3] = ff(lastPoint.v);
  1668.     GXSetPolygonParts(newShape, gxSelectToEnd, 1, (gxPolygons*)addPoly, gxRemoveDuplicatePointsEdit);
  1669.  
  1670.     // determine the amount we require the mouse to move before adding a new point
  1671.     penSize = FixedDivide(GXGetStylePen(newStyle), ff(2));
  1672.     if (penSize < ff(1))
  1673.         penSize = ff(1);
  1674.  
  1675.     do
  1676.         {
  1677.         GetMouse(¤tPoint);
  1678.         if     (
  1679.             (ff(ABS(currentPoint.h - lastPoint.h)) > penSize) ||
  1680.             (ff(ABS(currentPoint.v - lastPoint.v)) > penSize)
  1681.             )
  1682.             {
  1683.             // add the new point to the new shape
  1684.             lastPoint = currentPoint;
  1685.             addPoly[2] = ff(lastPoint.h);
  1686.             addPoly[3] = ff(lastPoint.v);
  1687.             GXSetPolygonParts(newShape, gxSelectToEnd, 1, (gxPolygons*)addPoly, gxRemoveDuplicatePointsEdit);
  1688.             GXDrawShape(newShape);
  1689.             }
  1690.         } while (StillDown());
  1691.     
  1692.     {
  1693.     Fixed            zoomFactor = ((GXDataPtr)pData)->zoomFactor;
  1694.     Fixed            shapeScale = FixedDivide(ff(1), zoomFactor);
  1695.     gxRectangle        pageSize, paperSize;
  1696.         
  1697.     // offset the shape by the scroll bars & margins
  1698.     GetCurrentPageAndPaper(pData, &pageSize, &paperSize);
  1699.     GXMoveShape(newShape, 
  1700.                 ff(GetControlValue(pData->hScroll)) + FixedMultiply(paperSize.left, zoomFactor),
  1701.                 ff(GetControlValue(pData->vScroll)) + FixedMultiply(paperSize.top, zoomFactor) );
  1702.  
  1703.     // scale the shape to the current scale factor
  1704.     GXScaleShape(newShape, shapeScale, shapeScale, 0, 0 );
  1705.     GXSetShapePen(newShape, FixedMultiply(GXGetShapePen(newShape), shapeScale) );
  1706.     }
  1707.     
  1708.     // add shape to the page
  1709.     {
  1710.     gxShape        annotationShape = (*((GXDataPtr)pData)->pageAnnotations)[((GXDataPtr)pData)->currentPage-1];
  1711.     
  1712.     if (!annotationShape)
  1713.         {
  1714.         annotationShape = GXNewShape(gxPictureType);
  1715.         (*((GXDataPtr)pData)->pageAnnotations)[((GXDataPtr)pData)->currentPage-1] = annotationShape;
  1716.         }
  1717.     if (annotationShape)
  1718.         GXSetPictureParts(annotationShape, 0, 0, 1, &newShape, nil, nil, nil);
  1719.     }
  1720.  
  1721.     // all done with our copies of the shape, style, and ink    
  1722.     GXDisposeShape(newShape);
  1723.     GXDisposeStyle(newStyle);
  1724.     GXDisposeInk(newInk);
  1725.     
  1726.     // we've touched the file
  1727.     pData->changed = true;
  1728.     
  1729.     return(anErr);
  1730.     
  1731. } // DoDrawingClick
  1732.  
  1733. // --------------------------------------------------------------------------------------------------------------
  1734.  
  1735. // Handle update/activate events behind Standard File
  1736. static pascal Boolean SaveDialogFilter(DialogPtr theDialog, EventRecord *theEvent,
  1737.                                       short *itemHit, void *myDataPtr)
  1738. {
  1739.     #pragma unused(myDataPtr)
  1740.  
  1741.     if (StdFilterProc(theDialog, theEvent, itemHit))
  1742.         return true;
  1743.  
  1744.     // Pass updates through (Activates are tricky...was mucking with Apple menu & thereby
  1745.     // drastically changing how the system handles the menu bar during our alert)
  1746.     if (theEvent->what == updateEvt /* || theEvent->what == activateEvt */ )
  1747.         {
  1748.         HandleEvent(theEvent);
  1749.         }
  1750.  
  1751.     return false;
  1752.  
  1753. } // SaveDialogFilter
  1754.  
  1755. #if GENERATINGCFM
  1756.     static RoutineDescriptor gSaveDialogFilterRD = BUILD_ROUTINE_DESCRIPTOR(uppModalFilterYDProcInfo, SaveDialogFilter);
  1757.     static ModalFilterYDUPP gSaveDialogFilter = &gSaveDialogFilterRD;
  1758. #else
  1759.     static ModalFilterYDUPP gSaveDialogFilter = NewModalFilterYDProc(SaveDialogFilter);
  1760. #endif
  1761.  
  1762. // --------------------------------------------------------------------------------------------------------------
  1763. #define kLoadAnnotations    true
  1764. #define kSaveAnnotations    false
  1765.  
  1766. static OSErr    LoadOrSaveAnnotations(WindowDataPtr pData, Boolean load)
  1767. {
  1768.     OSErr                anErr = noErr;
  1769.     short                i;
  1770.     short                oldResFile = CurResFile();
  1771.     userSpool             block;
  1772.     
  1773.     block.spool.spoolProcedure = gHandleSpoolProc;
  1774.     
  1775.     UseResFile(((GXDataPtr)pData)->printFileRefNum);
  1776.     for (i = 0; i < ((GXDataPtr)pData)->numberOfPages; ++i)
  1777.         {
  1778.         gxShape annotation = (*((GXDataPtr)pData)->pageAnnotations)[i];
  1779.         Handle    annotationHandle;
  1780.         
  1781.         block.spool.buffer = nil;
  1782.         block.spool.bufferSize = 0;
  1783.         if (load)
  1784.             {
  1785.             // load annotation, if any
  1786.             annotationHandle = Get1Resource(kAnnotationType, kAnnotationBaseID + i-1);
  1787.             if (annotationHandle)
  1788.                 {
  1789.                 block.data = annotationHandle;
  1790.                 annotation = GXUnflattenShape(&block.spool, 0, nil);
  1791.                 ReleaseResource(annotationHandle);
  1792.                 }
  1793.             else
  1794.                 {
  1795.                 annotation = nil;
  1796.                 }
  1797.             }
  1798.         else
  1799.             {
  1800.             // remove old annotation
  1801.             annotationHandle = Get1Resource(kAnnotationType, kAnnotationBaseID + i-1);
  1802.             if (annotationHandle)
  1803.                 RemoveResource(annotationHandle);
  1804.                 
  1805.             // add new annotation
  1806.             if (annotation)
  1807.                 {
  1808.                 block.spool.spoolProcedure = gHandleSpoolProc;
  1809.                 block.spool.buffer = nil;
  1810.                 block.spool.bufferSize = 0;
  1811.                 GXFlattenShape(annotation, 0, &block.spool);
  1812.                 annotationHandle = (Handle) block.data;
  1813.                 if (annotationHandle)
  1814.                     {
  1815.                     AddResource(annotationHandle, kAnnotationType, kAnnotationBaseID + i-1, "\p");
  1816.                     ReleaseResource(annotationHandle);
  1817.                     }
  1818.                 }
  1819.             }
  1820.             
  1821.         (*((GXDataPtr)pData)->pageAnnotations)[i] = annotation;
  1822.         }
  1823.     UpdateResFile(CurResFile());
  1824.     UseResFile(oldResFile);
  1825.     
  1826.     return(anErr);
  1827.     
  1828. } // LoadOrSaveAnnotations
  1829.  
  1830. // --------------------------------------------------------------------------------------------------------------
  1831. static OSErr    GXSaveAs(WindowRef pWindow, WindowDataPtr pData)
  1832. {
  1833.     OSErr                anErr = noErr;
  1834.     Boolean                replacing;
  1835.     FSSpec                fileSpec;
  1836.     NavReplyRecord        navReply;
  1837.     
  1838.     
  1839.     // ask where and how to save this document
  1840.     {
  1841.     Str255    defaultName;
  1842.     Point    where = {-1, -1};
  1843.     
  1844.     // setup for the call
  1845.     GetWTitle(pWindow, defaultName);
  1846.     SetCursor(&qd.arrow);
  1847.     
  1848.     // find out where the user wants the file
  1849.     if (gMachineInfo.haveNavigationServices)
  1850.     {        
  1851.         anErr = SaveFileDialog(defaultName, pData->originalFileType, 'ttxt', MyEventProc, &fileSpec, NULL, &replacing, &navReply);
  1852.         if ( anErr == userCanceledErr)
  1853.             anErr = eUserCanceled;
  1854.     }
  1855.     else
  1856.     {
  1857.         StandardFileReply    sfReply;
  1858.         
  1859.         CustomPutFile("\p", defaultName, &sfReply, 
  1860.                     sfPutDialogID, where,
  1861.                     nil, gSaveDialogFilter, nil, nil, nil);
  1862.  
  1863.         // map the cancel button into a cancelling error
  1864.         if (!sfReply.sfGood)
  1865.             anErr = eUserCanceled;
  1866.             
  1867.         replacing    = sfReply.sfReplacing;
  1868.         fileSpec    = sfReply.sfFile;
  1869.     }
  1870.     
  1871.     }
  1872.         
  1873.     // can't replace over other types    
  1874.     if (replacing)
  1875.         {
  1876.         FInfo    theInfo;
  1877.         
  1878.         FSpGetFInfo(&fileSpec, &theInfo);
  1879.         
  1880.         if ( 
  1881.             (theInfo.fdType != 'sjob') && 
  1882.             (theInfo.fdType != 'tjob') && 
  1883.             (theInfo.fdType != 'rjob') && 
  1884.             (theInfo.fdType != 'qjob') 
  1885.             )
  1886.             anErr = eDocumentWrongKind;
  1887.         }
  1888.     nrequire(anErr, StandardPutFile);
  1889.         
  1890.     GXSavePrintFile(((GXDataPtr)pData)->thePrintFile, &fileSpec);
  1891.     anErr = GXGetJobError(pData->hPrint);
  1892.  
  1893.  
  1894.     // FALL THROUGH EXCEPTION HANDLING
  1895. StandardPutFile:
  1896.  
  1897.     // if everything went okay
  1898.     if (anErr == noErr)
  1899.         {
  1900.         // update the window title 
  1901.         SetWTitle(pWindow, fileSpec.name);
  1902.     
  1903.         // save new location
  1904.         BlockMoveData(&fileSpec, &pData->fileSpec, sizeof(FSSpec));
  1905.  
  1906.         // update the refNum
  1907.         ((GXDataPtr)pData)->printFileRefNum = CurResFile();
  1908.         
  1909.         // and read in the current page
  1910.         anErr = GetCurrentPage((GXDataPtr) pData, true);
  1911.         }
  1912.         
  1913.     if (gMachineInfo.haveNavigationServices)
  1914.     {
  1915.         CompleteSave(&fileSpec, &navReply);
  1916.     }
  1917.     
  1918.     return anErr;
  1919.     
  1920. } // GXSaveAs
  1921.  
  1922. // --------------------------------------------------------------------------------------------------------------
  1923. // OOP INTERFACE ROUTINES
  1924. // --------------------------------------------------------------------------------------------------------------
  1925.  
  1926. static OSErr    GXCloseWindow(WindowRef pWindow, WindowDataPtr pData)
  1927. {
  1928. #pragma unused (pWindow)
  1929.  
  1930.     if (((GXDataPtr)pData)->pageAnnotations)
  1931.         {
  1932.         short    i;
  1933.         
  1934.         for (i = 0; i < ((GXDataPtr)pData)->numberOfPages; ++i)
  1935.             {
  1936.             gxShape annotation = (*((GXDataPtr)pData)->pageAnnotations)[i];
  1937.             
  1938.             if (annotation)
  1939.                 GXDisposeShape(annotation);
  1940.             }
  1941.         DisposeHandle((Handle) (((GXDataPtr)pData)->pageAnnotations) );
  1942.         ((GXDataPtr)pData)->pageAnnotations = nil;
  1943.         }
  1944.     
  1945.     if (((GXDataPtr)pData)->currentSelectionShape)
  1946.         {
  1947.         GXDisposeShape(((GXDataPtr)pData)->currentSelectionShape);
  1948.         ((GXDataPtr)pData)->currentSelectionShape = nil;
  1949.         }
  1950.                         
  1951.     if (((GXDataPtr)pData)->currentPageShape)
  1952.         {
  1953.         GXDisposeShape(((GXDataPtr)pData)->currentPageShape);
  1954.         ((GXDataPtr)pData)->currentPageShape = nil;
  1955.         }
  1956.     GXClosePrintFile( ((GXDataPtr)pData)->thePrintFile);
  1957.  
  1958.     GXDisposeViewPort( ((GXDataPtr)pData)->parentViewPort);
  1959.     GXDisposeViewPort( ((GXDataPtr)pData)->childViewPort);
  1960.  
  1961.     return(noErr);
  1962.     
  1963. } // GXCloseWindow
  1964.  
  1965. // --------------------------------------------------------------------------------------------------------------
  1966.  
  1967. static OSErr    GXUpdateWindow(WindowRef pWindow, WindowDataPtr pData)
  1968. {
  1969.     gxGraphicsError        anErr = noErr;    
  1970.  
  1971.     // draw informational area to the left of the horizontal scroll bar
  1972.     {
  1973.     FontInfo    theInfo;
  1974.     Rect        infoArea;
  1975.     RgnHandle    oldClip = NewRgn();
  1976.     Handle        theString;
  1977.     long        theStringSize;
  1978.     
  1979.     // save old clip and clip to the label area
  1980.     GetClip(oldClip);
  1981.     infoArea.left = 0;
  1982.     infoArea.right = pData->hScrollOffset-1;
  1983.     infoArea.bottom = GetWindowPort(pWindow)->portRect.bottom;
  1984.     infoArea.top = infoArea.bottom - kScrollBarSize;
  1985.     ClipRect(&infoArea);
  1986.         
  1987.     // draw the label
  1988.     TextFont(applFont);
  1989.     TextSize(9);
  1990.     GetFontInfo(&theInfo);
  1991.     theString = GetResource('LSTR', kLabelString);
  1992.     if (theString)
  1993.         {
  1994.         Handle    inString = NewHandle(sizeof(Str255));
  1995.         Str255    newString;
  1996.         Rect    labelArea = infoArea;
  1997.         
  1998.         // erase any old string we had there
  1999.         labelArea.right -= kZoomControlsWidth + kToolControlWidth;
  2000.         if (((GXDataPtr)pData)->numberOfPages > 1)
  2001.             labelArea.left += kPageControlsWidth;        
  2002.         EraseRect(&labelArea);
  2003.         
  2004.         // current page label
  2005.         NumToString(((GXDataPtr)pData)->currentPage, newString);
  2006.         SetHandleSize(inString, newString[0]);
  2007.         BlockMoveData(&newString[1], *inString, newString[0]);
  2008.         ReplaceText(theString, inString, "\p^0");
  2009.  
  2010.         // total page count label
  2011.         NumToString(((GXDataPtr)pData)->numberOfPages, newString);
  2012.         SetHandleSize(inString, newString[0]);
  2013.         BlockMoveData(&newString[1], *inString, newString[0]);
  2014.         ReplaceText(theString, inString, "\p^1");
  2015.  
  2016.         // scale factor label
  2017.         NumToString(FixedToInt( FixedMultiply(((GXDataPtr)pData)->zoomFactor, ff(100)) ), newString);
  2018.         SetHandleSize(inString, newString[0]);
  2019.         BlockMoveData(&newString[1], *inString, newString[0]);
  2020.         ReplaceText(theString, inString, "\p^2");
  2021.  
  2022.         // done with replace string content
  2023.         DisposeHandle(inString);
  2024.         
  2025.         // draw the label
  2026.         HLock(theString);
  2027.         theStringSize = GetHandleSize(theString);
  2028.         MoveTo(labelArea.left + ((labelArea.right - labelArea.left) >> 1) - (TextWidth(*theString, 0, theStringSize) >> 1), 
  2029.                 labelArea.top + ((labelArea.bottom - labelArea.top)>>1) + ((theInfo.ascent + theInfo.descent) >> 1) - theInfo.descent);
  2030.         DrawText(*theString, 0, theStringSize);
  2031.         ReleaseResource(theString);
  2032.         }
  2033.         
  2034.     // draw the current tool
  2035.         {
  2036.         Rect        toolArea = infoArea;
  2037.         CIconHandle    icon;
  2038.         
  2039.         toolArea.left = toolArea.right - kToolControlWidth;
  2040.         toolArea.right = toolArea.left + 32;
  2041.         toolArea.bottom = toolArea.top + 32;
  2042.         EraseRect(&toolArea);
  2043.         OffsetRect(&toolArea, -8, -8);
  2044.         
  2045.         icon = GetCIcon(kIconBase + ((GXDataPtr)pData)->contentClickMode);
  2046.         if (icon)
  2047.             {
  2048.             PlotCIconHandle(&toolArea, kAlignAbsoluteCenter, ttNone, icon);
  2049.             DisposeCIcon(icon);
  2050.             }
  2051.         }
  2052.  
  2053.     // draw the zoom controls
  2054.         {
  2055.         Rect    zoomArea = infoArea;
  2056.         zoomArea.left = zoomArea.right - kZoomControlsWidth - kToolControlWidth;
  2057.         zoomArea.right = zoomArea.left + 32;
  2058.         zoomArea.bottom = zoomArea.top + 32;
  2059.         
  2060.         PlotIconID(&zoomArea, ttNone, ttNone, kZoomControlPlain);
  2061.         }
  2062.                 
  2063.     // draw the left/right/page arrows
  2064.     if (((GXDataPtr)pData)->numberOfPages > 1)
  2065.         {
  2066.         Rect    arrowsRect;
  2067.         
  2068.         // erase any old arrow bits, including around the edges of the icon
  2069.         // needed when the window resizes
  2070.         arrowsRect = infoArea;
  2071.         arrowsRect.bottom = arrowsRect.top + 32;
  2072.         arrowsRect.right = arrowsRect.left + 34;
  2073.         EraseRect(&arrowsRect);
  2074.         
  2075.         // then draw the new arrows
  2076.         arrowsRect.left = infoArea.left + 2;
  2077.         arrowsRect.top = infoArea.top + 2;
  2078.         arrowsRect.right = arrowsRect.left + kPageControlsWidth;
  2079.         arrowsRect.bottom = arrowsRect.top + 32;
  2080.         PlotIconID(&arrowsRect, ttNone, ttNone, kPageControlPlain);
  2081.         }
  2082.     
  2083.     // frame the area
  2084.     MoveTo(infoArea.left, infoArea.top);
  2085.     LineTo(infoArea.right, infoArea.top);
  2086.  
  2087.     // restore old clip value
  2088.     SetClip(oldClip);
  2089.     DisposeRgn(oldClip);
  2090.     }
  2091.  
  2092.  
  2093.     // then draw the page shape and things around it
  2094.     {
  2095.     gxRectangle            pageSize, paperSize;    
  2096.     gxShape                tempShape, pageShape;
  2097.     gxMapping            thisMapping;
  2098.  
  2099.     // clip to the content area
  2100.     paperSize.left         = ff(pData->contentRect.left);
  2101.     paperSize.top         = ff(pData->contentRect.top);
  2102.     paperSize.right     = ff(pData->contentRect.right);
  2103.     paperSize.bottom     = ff(pData->contentRect.bottom);
  2104.     tempShape = GXNewRectangle(&paperSize);
  2105.     GXSetViewPortClip(((GXDataPtr)pData)->childViewPort, tempShape);
  2106.     GXDisposeShape(tempShape);
  2107.     
  2108.     // get the paper sizes, account for zoom factor
  2109.     GetCurrentPageAndPaper(pData, &pageSize, &paperSize);
  2110.     pageSize.left         = FixedMultiply(pageSize.left, ((GXDataPtr)pData)->zoomFactor);
  2111.     pageSize.right         = FixedMultiply(pageSize.right, ((GXDataPtr)pData)->zoomFactor);
  2112.     pageSize.top         = FixedMultiply(pageSize.top, ((GXDataPtr)pData)->zoomFactor);
  2113.     pageSize.bottom     = FixedMultiply(pageSize.bottom, ((GXDataPtr)pData)->zoomFactor);
  2114.     paperSize.left         = FixedMultiply(paperSize.left, ((GXDataPtr)pData)->zoomFactor);
  2115.     paperSize.right     = FixedMultiply(paperSize.right, ((GXDataPtr)pData)->zoomFactor);
  2116.     paperSize.top         = FixedMultiply(paperSize.top, ((GXDataPtr)pData)->zoomFactor);
  2117.     paperSize.bottom     = FixedMultiply(paperSize.bottom, ((GXDataPtr)pData)->zoomFactor);
  2118.     
  2119.     // offset by the scrolling amount    
  2120.     ResetMapping(&thisMapping);
  2121.     MoveMapping(&thisMapping, Long2Fix(-GetControlValue(pData->hScroll)) - paperSize.left ,
  2122.                 Long2Fix(-GetControlValue(pData->vScroll)) - paperSize.top );
  2123.  
  2124.     // make the paper shape
  2125.     tempShape = GXNewShape(gxFullType);
  2126.     GXSetTransformViewPorts(GXGetShapeTransform(tempShape), 1, & ((GXDataPtr)pData)->childViewPort);
  2127.     GXSetShapeFill(tempShape, gxEvenOddFill);
  2128.     GXSetShapeMapping(tempShape, &thisMapping);
  2129.     
  2130.     // make the page shape
  2131.     pageShape = GXNewRectangle(&pageSize);
  2132.     GXSetTransformViewPorts(GXGetShapeTransform(pageShape), 1, & ((GXDataPtr)pData)->childViewPort);
  2133.     GXSetShapeFill(pageShape, gxEvenOddFill);
  2134.     GXSetShapeMapping(pageShape, &thisMapping);
  2135.     
  2136.     // remove the page shape from the paper shape
  2137.     GXDifferenceShape(tempShape, pageShape);
  2138.  
  2139.     // draw the paper shape, dispose of it
  2140.     SetShapeGreyColorLevel(tempShape, 0xD000);    /* Set up light gray background */
  2141.     GXDrawShape(tempShape);
  2142.     GXDisposeShape(tempShape);
  2143.     
  2144.     // draw white on the page shape
  2145.     SetShapeGreyColorLevel(pageShape, 0xFFFF);    /* Set up white page */
  2146.     GXSetShapeFill(pageShape, gxEvenOddFill);
  2147.     GXDrawShape(pageShape);
  2148.     
  2149.     // frame the page shape
  2150.     SetShapeGreyColorLevel(pageShape, 0x8000);    /* Set up medium gray frame */
  2151.     GXSetShapeFill(pageShape, gxClosedFrameFill);
  2152.     GXDrawShape(pageShape);
  2153.     
  2154.     // draw the scroll bars and grow box now to give a nice appearence
  2155.     DrawControls(pWindow);
  2156.     DrawGrowIcon(pWindow);
  2157.  
  2158.     // draw the page data itself, clipped to the page
  2159.  
  2160.     {
  2161.     gxMapping    oldMapping, flipMapping;
  2162.     
  2163.     // get the page shape's old mapping, and make a copy to work with
  2164.     GXGetShapeMapping(((GXDataPtr)pData)->currentPageShape, &oldMapping);
  2165.  
  2166.     // run the clip through the inverse of the shape mapping to scale it properly
  2167.     GXInsetShape(pageShape, ff(1));
  2168.     ScaleMapping(&oldMapping, ((GXDataPtr)pData)->zoomFactor, ((GXDataPtr)pData)->zoomFactor, 0, 0);
  2169.     InvertMapping(&flipMapping, &oldMapping);
  2170.     GXMapShape(pageShape, &flipMapping);
  2171.     GXSetShapeFill(pageShape, gxEvenOddFill);
  2172.     GXSetShapeClip( ((GXDataPtr)pData)->currentPageShape, pageShape);
  2173.     
  2174.     // move the shape into position by offseting the viewPort
  2175.     GXGetViewPortMapping(((GXDataPtr)pData)->childViewPort, &thisMapping);    
  2176.     GXGetViewPortMapping(((GXDataPtr)pData)->childViewPort, &oldMapping);    
  2177.     ScaleMapping(&thisMapping, ((GXDataPtr)pData)->zoomFactor, ((GXDataPtr)pData)->zoomFactor, 0, 0);
  2178.     MoveMapping(&thisMapping, Long2Fix(-GetControlValue(pData->hScroll)) - paperSize.left ,
  2179.                 Long2Fix(-GetControlValue(pData->vScroll)) - paperSize.top );
  2180.     GXSetViewPortMapping(((GXDataPtr)pData)->childViewPort, &thisMapping);    
  2181.  
  2182.     /*
  2183.      *    Bracket the call to DrawShape with UseResFile, so that we put the
  2184.      *    document's resfile on top, allowing the translator (for QDShapes)
  2185.      *    to see our embedded fonts (if any) first.
  2186.      */
  2187.     {    short oldResFile = CurResFile();
  2188.     
  2189.         UseResFile(((GXDataPtr)pData)->printFileRefNum);
  2190.         GXDrawShape( ((GXDataPtr)pData)->currentPageShape);
  2191.         UseResFile(oldResFile);
  2192.     }
  2193.  
  2194.     
  2195.     // Draw the selection, if any
  2196.     {
  2197.     gxShape    selectionShape =  ((GXDataPtr)pData)->currentSelectionShape;
  2198.     gxShape    highlight;
  2199.     
  2200.     if (selectionShape)
  2201.         {
  2202.         
  2203.         // better be a layout shape to get hilights
  2204.         GXSetShapeType(selectionShape, gxLayoutType);
  2205.         
  2206.         // get the highlight
  2207.         highlight = GetCurrentSelectionHighlight(pData, true);
  2208.         GXDrawShape(highlight);
  2209.         GXDisposeShape(highlight);                        
  2210.         }
  2211.     }
  2212.  
  2213.     // Draw the overlay, if any
  2214.     {
  2215.     gxShape    annotationShape =  (*((GXDataPtr)pData)->pageAnnotations)[((GXDataPtr)pData)->currentPage-1];
  2216.     
  2217.     if (annotationShape)
  2218.         {
  2219.         GXSetShapeViewPorts(annotationShape, 1, &((GXDataPtr)pData)->childViewPort);
  2220.         GXDrawShape(annotationShape);
  2221.         }    
  2222.     }
  2223.  
  2224.     // restore viewPort's mapping (so we don't use it again next time)
  2225.     GXSetViewPortMapping(((GXDataPtr)pData)->childViewPort, &oldMapping);    
  2226.  
  2227.     
  2228.     }
  2229.     
  2230.     // done with the page shape
  2231.     GXDisposeShape(pageShape);
  2232.  
  2233.     DrawSelection(pData, &((GXDataPtr)pData)->selectionRectangle, &((GXDataPtr)pData)->patternPhase, false);
  2234.  
  2235.     GXGetGraphicsError(&anErr);
  2236.     }
  2237.     
  2238.     return(anErr);
  2239.     
  2240. } // GXUpdateWindow
  2241.  
  2242. // --------------------------------------------------------------------------------------------------------------
  2243.  
  2244. static OSErr    GXContentClick(WindowRef pWindow, WindowDataPtr pData, EventRecord *pEvent)
  2245. {
  2246.     OSErr            anErr = noErr;
  2247.     Point            clickPoint = pEvent->where;
  2248.     Rect            infoArea, labelArea, toolArea;
  2249.     Rect            zoomOutRect, zoomInRect, zoomsRect;
  2250.     RgnHandle        oldClip = NewRgn();
  2251.     Boolean            somethingHit = false;
  2252.     
  2253.     // convert to local space, calculate clickable areas    
  2254.     GlobalToLocal(&clickPoint);
  2255.     infoArea.left = 0;
  2256.     infoArea.right = pData->hScrollOffset-1;
  2257.     infoArea.bottom = GetWindowPort(pWindow)->portRect.bottom;
  2258.     infoArea.top = infoArea.bottom - kScrollBarSize;
  2259.  
  2260.     // clip to the info area
  2261.     GetClip(oldClip);
  2262.     ClipRect(&infoArea);
  2263.  
  2264.     // label area
  2265.     labelArea = infoArea;
  2266.     labelArea.right -= kZoomControlsWidth + kToolControlWidth;
  2267.     if (((GXDataPtr)pData)->numberOfPages > 1)
  2268.         labelArea.left += kPageControlsWidth;        
  2269.  
  2270.     // the tool pop up
  2271.     toolArea = infoArea;
  2272.     toolArea.left = toolArea.right - kToolControlWidth;
  2273.     
  2274.     // calculate the zoom in/out rects
  2275.     zoomInRect = infoArea;
  2276.     zoomInRect.right -= kToolControlWidth;
  2277.     zoomInRect.left = zoomInRect.right - 13;
  2278.     zoomOutRect = zoomInRect;
  2279.     OffsetRect(&zoomOutRect, -13, 0);
  2280.     zoomsRect = zoomOutRect;
  2281.     zoomsRect.bottom = zoomsRect.top + 32;
  2282.     zoomsRect.right = zoomsRect.left + 32;
  2283.  
  2284.     // deal with zoom in/out clicks
  2285.     if (TrackIn(&zoomInRect, clickPoint, &zoomsRect, kZoomControlRight, kZoomControlPlain))
  2286.         {
  2287.         somethingHit = true;
  2288.         SetZoom(pWindow, pData, FixedMultiply(((GXDataPtr)pData)->zoomFactor, ff(2)) );
  2289.         PlotIconID(&zoomsRect, ttNone, ttNone, kZoomControlPlain);
  2290.         }
  2291.  
  2292.     if (TrackIn(&zoomOutRect, clickPoint, &zoomsRect, kZoomControlLeft, kZoomControlPlain))
  2293.         {
  2294.         somethingHit = true;
  2295.         SetZoom(pWindow, pData, FixedDivide(((GXDataPtr)pData)->zoomFactor, ff(2)) );
  2296.         PlotIconID(&zoomsRect, ttNone, ttNone, kZoomControlPlain);
  2297.         }
  2298.  
  2299.     // deal with the options pop up
  2300.     if (PtInRect(clickPoint, &labelArea))
  2301.         {
  2302.         MenuHandle    popupMenu = GetMenu(kGXPopUpMenu);
  2303.         short        selectedItem;
  2304.         TextState    textState;
  2305.         Point        popPoint;
  2306.         char        bulletString[3];
  2307.         
  2308.         // figure out where to display the pop up
  2309.         popPoint.v = labelArea.top;
  2310.         popPoint.h = labelArea.left;
  2311.         LocalToGlobal(&popPoint);
  2312.  
  2313.         somethingHit = true;
  2314.         GetIntlTokenChar(tokenCenterDot, FontToScript(applFont), bulletString);
  2315.         
  2316.         // set up menu to be small sized
  2317.         TextFont(applFont);
  2318.         TextSize(9);
  2319.         DoUseWFont(&textState, pWindow, true);
  2320.         
  2321.         // set up the menu for selected items
  2322.         SetItemMark(popupMenu, iDontShowMargins, (((GXDataPtr)pData)->dontShowMargins) ? bulletString[1] : noMark);
  2323.         {
  2324.         ZoomTableEntry *pEntry = &gZoomTable[0];
  2325.         
  2326.         while (pEntry->menuItem != 0)
  2327.             {
  2328.             SetItemMark(popupMenu, pEntry->menuItem, (((GXDataPtr)pData)->zoomFactor == pEntry->zoomFactor) ? bulletString[1] : noMark);
  2329.             pEntry++;
  2330.             }
  2331.         }
  2332.         
  2333.         // conduct the menu
  2334.         InsertMenu(popupMenu, -1);
  2335.         selectedItem = PopUpMenuSelect(popupMenu, popPoint.v, popPoint.h, CountMItems(popupMenu)+1) & 0xFFFF;
  2336.  
  2337.         // restore menu sizes
  2338.         DoUseWFont(&textState, nil, false);
  2339.         DeleteMenu(kGXPopUpMenu);
  2340.         
  2341.         switch (selectedItem)
  2342.             {                
  2343.             // toggle show/hide margins
  2344.             case iDontShowMargins:
  2345.                 // flip the boolean
  2346.                 ((GXDataPtr)pData)->dontShowMargins = 1 - ((GXDataPtr)pData)->dontShowMargins;
  2347.                 
  2348.                 // force update and recalc the size of window
  2349.                 InvalRect(&GetWindowPort(pWindow)->portRect);
  2350.                 AdjustScrollBars(pWindow, true, true, nil);
  2351.                 break;
  2352.  
  2353.             // scale graphics to fit the window
  2354.             case iScaleToFit:
  2355.                 {
  2356.                 gxRectangle        pageSize, paperSize;
  2357.                 Fixed            horizScale, vertScale;
  2358.                 GrafPtr            pPort = (GrafPtr)GetWindowPort(pWindow);
  2359.                 
  2360.                 GetCurrentPageAndPaper(pData, &pageSize, &paperSize);
  2361.                 
  2362.                 pageSize.left = pageSize.top = 0;
  2363.                 pageSize.right = ff(pPort->portRect.right - kScrollBarSize);
  2364.                 pageSize.bottom = ff(pPort->portRect.bottom - kScrollBarSize);
  2365.                 
  2366.                 horizScale = FixedDivide(pageSize.right - pageSize.left, paperSize.right - paperSize.left);
  2367.                 vertScale = FixedDivide(pageSize.bottom - pageSize.top, paperSize.bottom - paperSize.top);
  2368.                 if (horizScale > vertScale)
  2369.                     SetZoom(pWindow, pData, vertScale);
  2370.                 else
  2371.                     SetZoom(pWindow, pData, horizScale);
  2372.                 }
  2373.                 break;
  2374.                 
  2375.             // absolute set scale cases
  2376.             default:
  2377.                 {
  2378.                 ZoomTableEntry *pEntry = &gZoomTable[0];
  2379.                 
  2380.                 while (pEntry->menuItem != 0)
  2381.                     {
  2382.                     if (selectedItem == pEntry->menuItem)
  2383.                         SetZoom(pWindow, pData, pEntry->zoomFactor);
  2384.                     pEntry++;
  2385.                     }
  2386.                 }
  2387.                 break;
  2388.             }
  2389.             
  2390.         }
  2391.         
  2392.     // deal with the tool pop up
  2393.     if (PtInRect(clickPoint, &toolArea))
  2394.         {
  2395.         MenuHandle    popupMenu = GetMenu(kGXToolMenu);
  2396.         short        selectedItem;
  2397.         Point        popPoint;
  2398.         short        i, numItems;
  2399.         
  2400.         // figure out where to display the pop up
  2401.         popPoint.v = toolArea.top;
  2402.         popPoint.h = toolArea.left;
  2403.         LocalToGlobal(&popPoint);
  2404.  
  2405.         // we've processed the mouse click
  2406.         somethingHit = true;
  2407.         
  2408.         // select our current item in the menu
  2409.         numItems = CountMItems(popupMenu);
  2410.         for (i = 1; i <= numItems; ++i)
  2411.             CheckItem(popupMenu, i, (i == ((GXDataPtr)pData)->contentClickMode) );
  2412.         
  2413.         // conduct the menu
  2414.         InsertMenu(popupMenu, -1);
  2415.         selectedItem = PopUpMenuSelect(popupMenu, popPoint.v, popPoint.h, numItems+1) & 0xFFFF;
  2416.         DeleteMenu(kGXPopUpMenu);
  2417.  
  2418.         // remember the item selected
  2419.         if (selectedItem != 0)
  2420.             ((GXDataPtr)pData)->contentClickMode = selectedItem;
  2421.             
  2422.         // invalidation the tool picture
  2423.         InvalRect(&toolArea);
  2424.         
  2425.         if (selectedItem != kSelectionTool)
  2426.             {
  2427.             // erase the old selection
  2428.             DrawSelection(pData, &((GXDataPtr)pData)->selectionRectangle, &((GXDataPtr)pData)->patternPhase, false);
  2429.     
  2430.             // clear the selection
  2431.             ((GXDataPtr)pData)->selectionRectangle.top         = 0;
  2432.             ((GXDataPtr)pData)->selectionRectangle.left        = 0;
  2433.             ((GXDataPtr)pData)->selectionRectangle.bottom    = 0;
  2434.             ((GXDataPtr)pData)->selectionRectangle.right    = 0;
  2435.     
  2436.             // draw the new selection
  2437.             DrawSelection(pData, &((GXDataPtr)pData)->selectionRectangle, &((GXDataPtr)pData)->patternPhase, true);
  2438.             }
  2439.         }
  2440.         
  2441.     // deal with clicks in page controls
  2442.     if (((GXDataPtr)pData)->numberOfPages > 1)
  2443.         {
  2444.         Rect    leftArrowRect, rightArrowRect, arrowsRect;
  2445.         Rect    gotoPageRect;
  2446.         
  2447.         // calculate the minus one page arrow        
  2448.         leftArrowRect.top         = infoArea.top + 2;
  2449.         leftArrowRect.bottom     = leftArrowRect.top + 32;
  2450.         leftArrowRect.left         = infoArea.left + 2;
  2451.         leftArrowRect.right     = leftArrowRect.left + 11;
  2452.                 
  2453.         // calculate the go to a particular page rect        
  2454.         gotoPageRect = leftArrowRect;
  2455.         OffsetRect(&gotoPageRect, 11, 0);
  2456.         gotoPageRect.right --;
  2457.  
  2458.         // calculate the plus one page arrow        
  2459.         rightArrowRect = gotoPageRect;
  2460.         OffsetRect(&rightArrowRect, 10, 0);
  2461.         
  2462.         // calculate sum of all areas
  2463.         arrowsRect = leftArrowRect;
  2464.         arrowsRect.left     = infoArea.left + 2;
  2465.         arrowsRect.right     = arrowsRect.left + kPageControlsWidth;
  2466.                     
  2467.         if (TrackIn(&leftArrowRect, clickPoint, &arrowsRect, kPageControlLeft, kPageControlPlain))
  2468.             {
  2469.             somethingHit = true;
  2470.             if (((GXDataPtr)pData)->currentPage > 1) 
  2471.                 anErr = GXCommand(pWindow, pData, cPreviousPage, 0);
  2472.             else
  2473.                 PlotIconID(&arrowsRect, ttNone, ttNone, kPageControlPlain);
  2474.             }
  2475.  
  2476.         if (TrackIn(&rightArrowRect, clickPoint, &arrowsRect, kPageControlRight, kPageControlPlain))
  2477.             {
  2478.             somethingHit = true;
  2479.             if (((GXDataPtr)pData)->currentPage < ((GXDataPtr)pData)->numberOfPages)
  2480.                 anErr = GXCommand(pWindow, pData, cNextPage, 0);
  2481.             else
  2482.                 PlotIconID(&arrowsRect, ttNone, ttNone, kPageControlPlain);
  2483.             }
  2484.             
  2485.         if (PtInRect(clickPoint, &gotoPageRect))
  2486.             {
  2487.             long    actualTicks;
  2488.             
  2489.             somethingHit = true;
  2490.             // pause, then check if the mouse is still down
  2491.             Delay(20, &actualTicks);
  2492.             
  2493.             // if still down, track preview window
  2494.             if (StillDown())
  2495.                 {
  2496.                 WindowRef    popWindow;
  2497.                 Rect        windowRect;
  2498.                 short        oldResFile = CurResFile();
  2499.                 
  2500.                 // put the print file on top
  2501.                 UseResFile(((GXDataPtr)pData)->printFileRefNum);
  2502.                 
  2503.                 // figure out where to place the pop up window, and then make it
  2504.                 windowRect.bottom     = arrowsRect.top - 2;
  2505.                 windowRect.left        = 2;
  2506.                 if (Count1Resources(kProxyType) > 0)
  2507.                     windowRect.top = windowRect.bottom - kPopUpWindowHeightLarge;
  2508.                 else
  2509.                     windowRect.top = windowRect.bottom - kPopUpWindowHeightSmall;
  2510.                 windowRect.right     = windowRect.left + kScrollAreaWidth + kPageControlsWidth + kZoomControlsWidth + kToolControlWidth - 4;
  2511.                     
  2512.                 LocalToGlobal(&TopLeft(windowRect));                
  2513.                 LocalToGlobal(&BotRight(windowRect));                
  2514.                 
  2515.                 popWindow = (WindowRef) NewCWindow(nil, &windowRect, "\p", true, plainDBox, (WindowPtr)-1, false, 0);
  2516.                 if (popWindow)
  2517.                     {            
  2518.                     long    oldValue = ((GXDataPtr)pData)->currentPage;
  2519.                     long    newValue = oldValue;
  2520.                     GrafPtr    popPort = (GrafPtr)GetWindowPort(popWindow);
  2521.                     
  2522.                     // draw initial location of the value
  2523.                     SetPort(popPort);
  2524.                     DrawPageSliderAndThumb(popWindow, oldValue, ((GXDataPtr)pData)->numberOfPages);
  2525.                                         
  2526.                     // track the mouse, updating the value as we go
  2527.                     while (StillDown())
  2528.                         {
  2529.                         GetMouse(&clickPoint);
  2530.                         if (PtInRect(clickPoint, &popPort->portRect))
  2531.                             {
  2532.                             newValue =     clickPoint.h
  2533.                                             *
  2534.                                         ((GXDataPtr)pData)->numberOfPages
  2535.                                             /
  2536.                                         (popPort->portRect.right - popPort->portRect.left) 
  2537.                                             + 1;
  2538.                                         
  2539.                             if (oldValue != newValue)
  2540.                                 {
  2541.                                 oldValue = newValue;
  2542.                                 DrawPageSliderAndThumb(popWindow, oldValue, ((GXDataPtr)pData)->numberOfPages);
  2543.                                 }
  2544.                             }
  2545.                         }
  2546.                         
  2547.                     // and done with the pop up window, return to main window
  2548.                     DisposeWindow(popWindow);
  2549.                     SetPort((GrafPtr)GetWindowPort(pWindow));
  2550.                     
  2551.                     // if we changed the value, make it so
  2552.                     if (newValue != ((GXDataPtr)pData)->currentPage)
  2553.                         {
  2554.                         ((GXDataPtr)pData)->currentPage = newValue;
  2555.                         anErr = GetCurrentPage((GXDataPtr) pData, true);
  2556.                         InvalRect(&GetWindowPort(pWindow)->portRect);
  2557.                         }
  2558.                     }
  2559.                     
  2560.                 // restore resource chain
  2561.                 UseResFile(oldResFile);
  2562.                 }
  2563.             else
  2564.                 {
  2565.                 // otherwise, do the goto dialog box
  2566.                 anErr = GXCommand(pWindow, pData, cGotoPage, 0);
  2567.                 }
  2568.                 
  2569.             } // if (click in goto page area)
  2570.             
  2571.         } // if (> 1 page)
  2572.  
  2573.     // restore clip
  2574.     SetClip(oldClip);
  2575.     DisposeRgn(oldClip);
  2576.     
  2577.     // nothing matched so far, deal with selecting the contents
  2578.     if (!somethingHit)
  2579.         {
  2580.         Rect    selectionRect = ((GXDataPtr)pData)->selectionRectangle;
  2581.         
  2582.         
  2583.         OffsetRect(&selectionRect, -GetControlValue(pData->hScroll), -GetControlValue(pData->vScroll));
  2584.         if ( (gMachineInfo.haveDragMgr) && (PtInRect(clickPoint, &selectionRect)) )
  2585.             {
  2586.             ((GXDataPtr)pData)->tempDragShape = nil;
  2587.             DragAndDropArea(pWindow, pData, pEvent, 
  2588.                                 &selectionRect);
  2589.                 
  2590.                                 
  2591.             if ( ((GXDataPtr)pData)->tempDragShape )
  2592.                 GXDisposeShape( ((GXDataPtr)pData)->tempDragShape );
  2593.             }
  2594.         else
  2595.             {
  2596.             LongRect        docRect;
  2597.             Rect            contentRect;
  2598.             
  2599.             contentRect = GetWindowPort(pWindow)->portRect;
  2600.             contentRect.right -= kScrollBarSize;
  2601.             contentRect.bottom -= kScrollBarSize;
  2602.             
  2603.             if (PtInRect(clickPoint, &contentRect))
  2604.                 {
  2605.                 switch (((GXDataPtr)pData)->contentClickMode)
  2606.                     {
  2607.                     case kSelectionTool:
  2608.                         GXGetDocumentRect(pWindow, pData, &docRect, false);
  2609.                         contentRect.top     = docRect.top;
  2610.                         contentRect.left     = docRect.left;
  2611.                         contentRect.bottom     = docRect.bottom;
  2612.                         contentRect.right     = docRect.right;
  2613.                         
  2614.                         anErr = SelectContents(pWindow, pData, pEvent, 
  2615.                                             &((GXDataPtr)pData)->selectionRectangle, &contentRect, 
  2616.                                             &((GXDataPtr)pData)->patternPhase);
  2617.                 
  2618.                         // existing text selection? clear the highlight
  2619.                         if (((GXDataPtr)pData)->currentSelectionShape)
  2620.                             {
  2621.                             InvalRect(&GetWindowPort(pWindow)->portRect);
  2622.                             
  2623.                             ClearCurrentSelection((GXDataPtr)pData);
  2624.                             }
  2625.                         break;
  2626.  
  2627.                     case kRedMarkerTool:
  2628.                         DoDrawingClick(pWindow, pData, clickPoint, pEvent);
  2629.                         break;
  2630.                         
  2631.                     } // switch (mode)
  2632.                     
  2633.                 } // click in content rect
  2634.             }
  2635.         }
  2636.         
  2637.     return(anErr);
  2638.         
  2639. } // GXContentClick
  2640.  
  2641. // --------------------------------------------------------------------------------------------------------------
  2642.  
  2643. static OSErr    GXAdjustMenus(WindowRef pWindow, WindowDataPtr pData)
  2644. {
  2645. #pragma unused (pWindow)
  2646.  
  2647.     OSErr anErr = noErr;
  2648.     
  2649.     EnableCommand(cSaveAs);
  2650.  
  2651.     if (((GXDataPtr)pData)->numberOfPages > 1)
  2652.         {
  2653.         if (((GXDataPtr)pData)->currentPage < ((GXDataPtr)pData)->numberOfPages)
  2654.             EnableCommand(cNextPage);
  2655.             
  2656.         if (((GXDataPtr)pData)->currentPage > 1)
  2657.             EnableCommand(cPreviousPage);
  2658.         
  2659.         EnableCommand(cGotoPage);
  2660.         }
  2661.         
  2662.     if (!EmptyRect( &((GXDataPtr)pData)->selectionRectangle) )
  2663.         EnableCommand(cCopy);
  2664.  
  2665.     {
  2666.     LongRect        docRect;
  2667.     Rect            shortDocRect;
  2668.     
  2669.     // find out the size of the document            
  2670.     GXGetDocumentRect(pWindow, pData, &docRect, false);
  2671.     LongRectToRect(&docRect, &shortDocRect);
  2672.     if     (EqualRect(&shortDocRect, &((GXDataPtr)pData)->selectionRectangle))
  2673.         ChangeCommandName(cSelectAll, kMiscStrings, iSelectNoneCommand);
  2674.     else
  2675.         ChangeCommandName(cSelectAll, kMiscStrings, iSelectAllCommand);
  2676.     }
  2677.     EnableCommand(cSelectAll);
  2678.     
  2679.     EnableCommand(cFind);
  2680.     if (gFindString[0] != 0)
  2681.         EnableCommand(cFindAgain);
  2682.     
  2683.     return(anErr);
  2684.     
  2685. } // GXAdjustMenus
  2686.  
  2687. // --------------------------------------------------------------------------------------------------------------
  2688.  
  2689. OSErr    GXCommand(WindowRef pWindow, WindowDataPtr pData, short commandID, long menuResult)
  2690. {
  2691. #pragma unused (menuResult)
  2692.  
  2693.     OSErr    anErr = noErr;
  2694.         
  2695.     switch (commandID)
  2696.         {
  2697.         case cSave:
  2698.             GXSavePrintFile(((GXDataPtr)pData)->thePrintFile, nil);
  2699.             anErr = GXGetJobError(pData->hPrint);
  2700.             if (anErr == noErr)
  2701.                 anErr = LoadOrSaveAnnotations(pData, kSaveAnnotations);
  2702.                 
  2703.             // if everything went okay, then clear the changed bit
  2704.             if (anErr == noErr)
  2705.                 pData->changed = false;
  2706.             break;
  2707.             
  2708.         case cSaveAs:
  2709.             anErr = GXSaveAs(pWindow, pData);
  2710.             if (anErr == noErr)
  2711.                 anErr = LoadOrSaveAnnotations(pData, kSaveAnnotations);
  2712.  
  2713.             // if everything went okay, then clear the changed bit
  2714.             if (anErr == noErr)
  2715.                 pData->changed = false;
  2716.             break;
  2717.             
  2718.         case cFind:
  2719.             if (ConductFindOrReplaceDialog(kFindWindowID) == cancel)    
  2720.                 break;
  2721.             
  2722.             // start search at top of page
  2723.             ((GXDataPtr)pData)->currentShapeIndex = 0;
  2724.             
  2725.         // fall through from find
  2726.         case cFindAgain:
  2727.             {
  2728.             Boolean    isBackwards = ((gEvent.modifiers & shiftKey) != 0);
  2729.             
  2730.             SetWatchCursor();
  2731.  
  2732.             if (!PerformNextFind(pWindow, pData, gFindString, gCaseSensitive, isBackwards, gWrapAround))
  2733.                 SysBeep(1);
  2734.             else
  2735.                 ScrollFoundShapeIntoView(pWindow, pData);
  2736.                 
  2737.             SetCursor(&qd.arrow);
  2738.             }
  2739.             break;
  2740.  
  2741.         case cCopy:
  2742.             {
  2743.             gxShape            cullShape = GetSelectedShape(pData);
  2744.  
  2745.             if (cullShape)
  2746.                 {
  2747.                 // done with the shape now
  2748.                 ShapeToScrap(cullShape);
  2749.                 GXDisposeShape(cullShape);
  2750.                 }
  2751.             }
  2752.             break;
  2753.         
  2754.         case cSelectAll:
  2755.             {
  2756.             LongRect        docRect;
  2757.             Rect            shortDocRect;
  2758.             
  2759.             // find out the size of the document            
  2760.             GXGetDocumentRect(pWindow, pData, &docRect, false);
  2761.  
  2762.             // erase the old selection
  2763.             DrawSelection(pData, &((GXDataPtr)pData)->selectionRectangle, &((GXDataPtr)pData)->patternPhase, false);
  2764.             
  2765.             LongRectToRect(&docRect, &shortDocRect);
  2766.             if     (EqualRect(&shortDocRect, &((GXDataPtr)pData)->selectionRectangle))
  2767.                 {
  2768.                 ((GXDataPtr)pData)->selectionRectangle.top         = 0;
  2769.                 ((GXDataPtr)pData)->selectionRectangle.left        = 0;
  2770.                 ((GXDataPtr)pData)->selectionRectangle.bottom    = 0;
  2771.                 ((GXDataPtr)pData)->selectionRectangle.right    = 0;
  2772.                 }
  2773.             else
  2774.                 {
  2775.                 ((GXDataPtr)pData)->selectionRectangle.top         = docRect.top;
  2776.                 ((GXDataPtr)pData)->selectionRectangle.left        = docRect.left;
  2777.                 ((GXDataPtr)pData)->selectionRectangle.bottom    = docRect.bottom;
  2778.                 ((GXDataPtr)pData)->selectionRectangle.right    = docRect.right;
  2779.                 }
  2780.  
  2781.             // draw the new selection
  2782.             DrawSelection(pData, &((GXDataPtr)pData)->selectionRectangle, &((GXDataPtr)pData)->patternPhase, true);
  2783.             }
  2784.             break;
  2785.  
  2786.         case cPageSetup:
  2787.             DoPageSetup(pWindow);
  2788.             anErr = GetCurrentPage((GXDataPtr) pData, false);
  2789.             InvalRect(&GetWindowPort(pWindow)->portRect);
  2790.             anErr = eActionAlreadyHandled;
  2791.             break;
  2792.             
  2793.         case cNextPage:
  2794.             ((GXDataPtr)pData)->currentPage++;
  2795.             anErr = GetCurrentPage((GXDataPtr) pData, true);
  2796.             InvalRect(&GetWindowPort(pWindow)->portRect);
  2797.             if (anErr == noErr)
  2798.                 anErr = eActionAlreadyHandled;
  2799.             break;
  2800.         
  2801.         case cPreviousPage:
  2802.             ((GXDataPtr)pData)->currentPage--;
  2803.             anErr = GetCurrentPage((GXDataPtr) pData, true);
  2804.             InvalRect(&GetWindowPort(pWindow)->portRect);
  2805.             if (anErr == noErr)
  2806.                 anErr = eActionAlreadyHandled;
  2807.             break;
  2808.         
  2809.         case cGotoPage:
  2810.             switch (menuResult)
  2811.                 {
  2812.                 case cGotoFirst:
  2813.                     ((GXDataPtr)pData)->currentPage = 1;
  2814.                     anErr = GetCurrentPage((GXDataPtr) pData, true);
  2815.                     InvalRect(&GetWindowPort(pWindow)->portRect);
  2816.                     break;
  2817.  
  2818.                 case cGotoLast:
  2819.                     ((GXDataPtr)pData)->currentPage = ((GXDataPtr)pData)->numberOfPages;
  2820.                     anErr = GetCurrentPage((GXDataPtr) pData, true);
  2821.                     InvalRect(&GetWindowPort(pWindow)->portRect);
  2822.                     break;
  2823.                     
  2824.                 default:
  2825.                     {
  2826.                     DialogRef    dPtr;
  2827.                     short        hit;
  2828.                     
  2829.                     dPtr = GetNewDialog(kGotoPageDialogID, nil, (WindowRef)-1);
  2830.                     if (dPtr)
  2831.                         {
  2832.                         short    theType;
  2833.                         Handle    theHandle;
  2834.                         Rect    theRect;
  2835.                         Str255    theString;
  2836.                         
  2837.                         GetDialogItem(dPtr, 4, &theType, &theHandle, &theRect);
  2838.                         NumToString(((GXDataPtr)pData)->currentPage, theString);
  2839.                         SetDialogItemText(theHandle, theString);
  2840.                         SelectDialogItemText(dPtr, 4, 0, 32767);
  2841.  
  2842.                         NumToString(((GXDataPtr)pData)->numberOfPages, theString);
  2843.                         ParamText(theString, "\p", "\p", "\p");
  2844.                         
  2845.                         SetDialogDefaultItem(dPtr, ok);
  2846.                         SetDialogCancelItem(dPtr, cancel);
  2847.                         BeginMovableModal();
  2848.                         
  2849.                         do
  2850.                             {
  2851.                             MovableModalDialog(nil, &hit);
  2852.                             
  2853.                             if (hit == ok)
  2854.                                 {
  2855.                                 long    tempLong;
  2856.                                 
  2857.                                 // convert to a page number, find and report errors
  2858.                                 GetDialogItemText(theHandle, theString);
  2859.                                 StringToNum(theString, &tempLong);
  2860.                                 if (tempLong < 1) 
  2861.                                     {
  2862.                                     SysBeep(1);
  2863.                                     tempLong = 1;
  2864.                                     hit = 0;
  2865.                                     }
  2866.                                 if (tempLong > ((GXDataPtr)pData)->numberOfPages)
  2867.                                     {
  2868.                                     tempLong = ((GXDataPtr)pData)->numberOfPages;
  2869.                                     hit = 0;
  2870.                                     }
  2871.                                     
  2872.                                 // if we have an error, we try again, otherwise we go to the page
  2873.                                 if (hit == 0)
  2874.                                     {
  2875.                                     SysBeep(1);
  2876.                                     NumToString(tempLong, theString);
  2877.                                     SetDialogItemText(theHandle, theString);
  2878.                                     SelectDialogItemText(dPtr, 4, 0, 32767);
  2879.                                     }
  2880.                                 else
  2881.                                     {
  2882.                                     ((GXDataPtr)pData)->currentPage = tempLong;
  2883.                                     anErr = GetCurrentPage((GXDataPtr) pData, true);
  2884.                                     InvalRect(&GetWindowPort(pWindow)->portRect);
  2885.                                     }
  2886.                                 }
  2887.                             } while ((hit != ok) && (hit != cancel));
  2888.                             
  2889.                         DisposeDialog(dPtr);
  2890.                         EndMovableModal();
  2891.                         }
  2892.                         
  2893.                     }
  2894.                     break;
  2895.                     
  2896.                 }
  2897.             if (anErr == noErr)
  2898.                 anErr = eActionAlreadyHandled;
  2899.             break;
  2900.         
  2901.         }
  2902.     
  2903.     return(anErr);
  2904.     
  2905. } // GXCommand
  2906.  
  2907. // --------------------------------------------------------------------------------------------------------------
  2908. static OSErr    GXFilePrintPage(WindowRef pWindow, WindowDataPtr pData,
  2909.                     Rect * pageRect, long *pageNum)
  2910. {
  2911. #pragma unused (pWindow, pageRect)
  2912.  
  2913.     OSErr        anErr = noErr;
  2914.     gxShape     thisShape;
  2915.     gxFormat     thisFormat;
  2916.     
  2917.     GXReadPrintFilePage(((GXDataPtr)pData)->thePrintFile, *pageNum, 0, nil, &thisFormat, &thisShape);
  2918.     anErr = GXGetJobError(pData->hPrint);
  2919.     nrequire(anErr, ReadPrintFilePage);
  2920.  
  2921.     GXPrintPage(pData->hPrint, *pageNum, thisFormat, thisShape);
  2922.     anErr = GXGetJobError(pData->hPrint);
  2923.     nrequire(anErr, PrintPage);
  2924.  
  2925.     GXDisposeFormat(thisFormat);
  2926.     GXDisposeShape(thisShape);
  2927.  
  2928. // FALL THROUGH EXCEPTION HANDLING
  2929. PrintPage:
  2930. ReadPrintFilePage:
  2931.     // tell it to stop printing when we reach the end
  2932.     if (*pageNum >= ((GXDataPtr)pData)->numberOfPages)
  2933.         *pageNum = -1;
  2934.     
  2935.     return(anErr);
  2936.     
  2937. } // GXFilePrintPage
  2938.  
  2939. // --------------------------------------------------------------------------------------------------------------
  2940.  
  2941. OSErr    GXGetDocumentRect(WindowRef pWindow, WindowDataPtr pData, 
  2942.             LongRect * documentRectangle, Boolean forGrow)
  2943. {
  2944. #pragma unused (pWindow, forGrow)
  2945.  
  2946.     gxRectangle        pageSize, paperSize;
  2947.     
  2948.     GetCurrentPageAndPaper(pData, &pageSize, &paperSize);
  2949.  
  2950.     documentRectangle->left = 0;
  2951.     documentRectangle->top = 0;
  2952.     documentRectangle->bottom = FixedMultiply(paperSize.bottom - paperSize.top, ((GXDataPtr)pData)->zoomFactor) >> 16;
  2953.     documentRectangle->right = FixedMultiply(paperSize.right - paperSize.left, ((GXDataPtr)pData)->zoomFactor) >> 16;
  2954.         
  2955.     return(noErr);
  2956.     
  2957. } // GXGetDocumentRect
  2958.  
  2959. // --------------------------------------------------------------------------------------------------------------
  2960.  
  2961. static long GXCalculateIdleTime(WindowRef pWindow, WindowDataPtr pData)
  2962. {
  2963. #pragma unused (pWindow)
  2964.  
  2965.     if (!EmptyRect( &((GXDataPtr)pData)->selectionRectangle))
  2966.         return(0);
  2967.     else
  2968.         return(kMaxWaitTime);
  2969.         
  2970. } // GXCalculateIdleTime
  2971.  
  2972. // --------------------------------------------------------------------------------------------------------------
  2973.  
  2974. static Boolean    GXFilterEvent(WindowRef pWindow, WindowDataPtr pData, EventRecord *pEvent)
  2975. {
  2976.     if     (
  2977.         (!gMachineInfo.amInBackground) &&
  2978.         (pEvent->what == nullEvent) &&
  2979.         (pWindow == FrontWindow()) &&
  2980.         (EmptyRgn( ((WindowPeek)pWindow)->updateRgn)) &&
  2981.         (MOVESELECTION(pEvent->when) )
  2982.         )
  2983.         {
  2984.         // erase the old
  2985.         DrawSelection(pData, &((GXDataPtr)pData)->selectionRectangle, &((GXDataPtr)pData)->patternPhase, false);
  2986.         
  2987.         // draw the new, moving onto the next pattern
  2988.         DrawSelection(pData, &((GXDataPtr)pData)->selectionRectangle, &((GXDataPtr)pData)->patternPhase, true);
  2989.         }
  2990.         
  2991.     return(false);
  2992.     
  2993. } // GXFilterEvent
  2994.  
  2995. // --------------------------------------------------------------------------------------------------------------
  2996.  
  2997. static OSErr    GXDragAddFlavors(WindowRef pWindow, WindowDataPtr pData, DragReference theDragRef)
  2998. {
  2999. #pragma unused (pWindow)
  3000.  
  3001.     OSErr    anErr = noErr;
  3002.     
  3003.     SetDragSendProc(theDragRef, gGXSendDataProc, nil);
  3004.     AddDragItemFlavor(theDragRef, (unsigned long)pData, 'qdgx', nil, 0, 0);
  3005.     AddDragItemFlavor(theDragRef, (unsigned long)pData, 'PICT', nil, 0, 0);
  3006.     
  3007.     return(anErr);
  3008.     
  3009. } // GXDragAddFlavors
  3010.  
  3011. // --------------------------------------------------------------------------------------------------------------
  3012.  
  3013. static OSErr    GXAdjustCursor(WindowRef pWindow, WindowDataPtr pData, Point * localMouse, Rect * globalRect)
  3014. {
  3015. #pragma unused (pWindow, globalRect)
  3016.  
  3017.     OSErr            anErr = noErr;
  3018.     Handle        theCursor;
  3019.     Rect            selectionRect = ((GXDataPtr)pData)->selectionRectangle;
  3020.     
  3021.     OffsetRect(&selectionRect, -GetControlValue(pData->hScroll), -GetControlValue(pData->vScroll));
  3022.     if (!PtInRect(*localMouse, &selectionRect) )
  3023.         {
  3024.         short    cursorID;
  3025.         Boolean    colorCursor;
  3026.         
  3027.         cursorID = ((GXDataPtr)pData)->contentClickMode;
  3028.         if (cursorID == kSelectionTool)
  3029.             {
  3030.             colorCursor = false;
  3031.             cursorID = crossCursor;
  3032.             }
  3033.         else
  3034.             {
  3035.             colorCursor = true;
  3036.             cursorID += kIconBase;
  3037.             }
  3038.             
  3039.         if (colorCursor)
  3040.             theCursor = (Handle)GetCCursor(cursorID);
  3041.         else
  3042.             theCursor = (Handle)GetCursor(cursorID);
  3043.         if (theCursor)
  3044.             {
  3045.             if (colorCursor)
  3046.                 {
  3047.                 SetCCursor((CCrsrHandle)theCursor);
  3048.                 DisposeCCursor((CCrsrHandle)theCursor);
  3049.                 }
  3050.             else
  3051.                 {
  3052.                 char    oldState;
  3053.                 
  3054.                 oldState = HGetState(theCursor);
  3055.                 HLock((Handle) theCursor);
  3056.                 SetCursor(*(CursHandle)theCursor);
  3057.                 HSetState(theCursor, oldState);
  3058.                 }
  3059.             anErr = eActionAlreadyHandled;
  3060.             }
  3061.         }
  3062.     return(anErr);
  3063.     
  3064. } // GXAdjustCursor
  3065.  
  3066. // --------------------------------------------------------------------------------------------------------------
  3067.  
  3068. static OSErr    GXMakeWindow(WindowRef pWindow, WindowDataPtr pData)
  3069. {
  3070.     OSErr                anErr = noErr;
  3071.     
  3072.     pData->pCloseWindow         = (CloseWindowProc)            GXCloseWindow;
  3073.     pData->pAdjustMenus         = (AdjustMenusProc)            GXAdjustMenus;
  3074.     pData->pCommand                = (CommandProc)                GXCommand;
  3075.     pData->pUpdateWindow         = (UpdateWindowProc)        GXUpdateWindow;
  3076.     pData->pContentClick         = (ContentClickProc)        GXContentClick;
  3077.     pData->pGetDocumentRect     = (GetDocumentRectProc)        GXGetDocumentRect;
  3078.     pData->pPrintPage             = (PrintPageProc)            GXFilePrintPage;
  3079.     pData->pFilterEvent             = (FilterEventProc)            GXFilterEvent;
  3080.     pData->pCalculateIdleTime    = (CalculateIdleTimeProc)    GXCalculateIdleTime;
  3081.     pData->pAdjustCursor        = (AdjustCursorProc)        GXAdjustCursor;
  3082.     pData->pDragAddFlavors        = (DragAddFlavorsProc)        GXDragAddFlavors;
  3083.     
  3084.     pData->documentOutputsGX    = true;
  3085.     pData->hasGrow                = true;
  3086.     pData->minHSize                = kMinGXDocSize + kScrollAreaWidth + kZoomControlsWidth + kToolControlWidth;
  3087.     pData->hScrollAmount        = 10;
  3088.     pData->vScrollAmount        = 10;
  3089.     pData->hScrollOffset        = kScrollAreaWidth + kZoomControlsWidth + kToolControlWidth;
  3090.     
  3091.     // default the job info, which we need to have
  3092.     anErr = DoDefault(pData);
  3093.     nrequire(anErr, DoDefault);
  3094.  
  3095.     ((GXDataPtr)pData)->thePrintFile = GXOpenPrintFile(pData->hPrint, &pData->fileSpec, fsRdWrPerm);
  3096.     anErr = GXGetJobError(pData->hPrint);
  3097.     nrequire(anErr, OpenPrintFile);
  3098.  
  3099.     /*
  3100.      *    The assumption here is that the GXOpenPrintFile leaves the resfile on top.
  3101.      *    We need this refnum so that any resource handles the translator gets will
  3102.      *    match those that GXOpenPrintFile used for calls to GXNewFont.  See the call
  3103.      *    to GXDrawShape in GXUpdateWindow
  3104.      */
  3105.     ((GXDataPtr)pData)->printFileRefNum = CurResFile();
  3106.  
  3107.     // close down other paths to the file -- because we don't need them
  3108.     if (pData->resRefNum != -1)
  3109.         {
  3110.         CloseResFile(pData->resRefNum);
  3111.         pData->resRefNum = -1;
  3112.         }
  3113.     if (pData->dataRefNum != -1)
  3114.         {
  3115.         FSClose(pData->dataRefNum);
  3116.         pData->dataRefNum = -1;
  3117.         }
  3118.         
  3119.     // default to normal printing -- so if the user prints, we go to normal mode at first
  3120.     {
  3121.     Collection    jobCollection = GXGetJobCollection(pData->hPrint);
  3122.     gxJobInfo    theInfo;
  3123.     long        theSize = sizeof(theInfo);
  3124.     
  3125.     if (GetCollectionItem(jobCollection, gxJobTag, gxPrintingTagID, &theSize, &theInfo) == noErr)
  3126.         {
  3127.         theInfo.priority = gxPrintJobASAP;
  3128.         AddCollectionItem(jobCollection, gxJobTag, gxPrintingTagID, theSize, &theInfo);
  3129.         }
  3130.     
  3131.     }
  3132.     
  3133.     // by default we have no pages
  3134.     ((GXDataPtr)pData)->numberOfPages        = GXCountPrintFilePages(((GXDataPtr)pData)->thePrintFile);
  3135.     ((GXDataPtr)pData)->currentPage            = 1;
  3136.     ((GXDataPtr)pData)->zoomFactor            = ff(1);
  3137.     ((GXDataPtr)pData)->contentClickMode    = kSelectionTool;
  3138.     anErr = GXGetJobError(pData->hPrint);
  3139.     if ( (anErr == noErr) && (((GXDataPtr)pData)->numberOfPages == 0) )
  3140.         anErr = eDocumentContainsNoPages;
  3141.     nrequire(anErr, GXCountPrintFilePages);
  3142.     
  3143.     if (((GXDataPtr)pData)->numberOfPages > 1)
  3144.         pData->hScrollOffset += kPageControlsWidth;
  3145.         
  3146.     ((GXDataPtr)pData)->pageAnnotations = (gxShape**) NewHandleClear( (((GXDataPtr)pData)->numberOfPages * sizeof(gxShape)) );
  3147.     anErr = MemError();
  3148.     if (anErr == noErr)
  3149.         anErr = LoadOrSaveAnnotations(pData, kLoadAnnotations);
  3150.     nrequire(anErr, FailedToAllocateAnnotation);
  3151.     
  3152.     // set up so we can draw inside of this window
  3153.     ((GXDataPtr)pData)->parentViewPort = GXNewWindowViewPort((WindowPtr)pWindow);
  3154.     ((GXDataPtr)pData)->childViewPort = GXNewViewPort(gxScreenViewDevices);
  3155.     GXSetViewPortParent(((GXDataPtr)pData)->childViewPort, ((GXDataPtr)pData)->parentViewPort);
  3156.     GXSetViewPortAttributes(((GXDataPtr)pData)->childViewPort, gxAlwaysGridPort);
  3157.     GXSetViewPortDither(((GXDataPtr)pData)->childViewPort, 4);
  3158.     
  3159.     // fetch the current page
  3160.     anErr = GetCurrentPage((GXDataPtr) pData, true);
  3161.     nrequire(anErr, GetCurrentPage);
  3162.     
  3163.     // if this document contains PostScript do a warning
  3164.     {
  3165.     gxTranslatedDocumentInfo theInfo;
  3166.     long theSize = sizeof(theInfo);
  3167.     
  3168.     if     (
  3169.         (GetCollectionItem(GXGetJobCollection(pData->hPrint),
  3170.                             gxTranslatedDocumentTag,
  3171.                             gxPrintingTagID,
  3172.                             &theSize,
  3173.                             &theInfo
  3174.                             ) == noErr) &&
  3175.         (theInfo.translatorInfo & gxContainsPostScript)
  3176.         )
  3177.         ConductErrorDialog(eDocumentContainsPS, cOpen, ok);
  3178.     }
  3179.     
  3180.     return(anErr);
  3181.     
  3182. // EXCEPTION HANDLING
  3183. GetCurrentPage:
  3184. FailedToAllocateAnnotation:
  3185. GXCountPrintFilePages:
  3186.     GXClosePrintFile( ((GXDataPtr)pData)->thePrintFile);
  3187.     
  3188. OpenPrintFile:
  3189.     GXDisposeJob(pData->hPrint);
  3190.         
  3191. DoDefault:
  3192.     return(anErr);
  3193.     
  3194. } // GXMakeWindow
  3195.  
  3196.  
  3197. // --------------------------------------------------------------------------------------------------------------
  3198.  
  3199. OSErr    GXPreflightWindow(PreflightPtr pPreflightData)
  3200. {    
  3201.     pPreflightData->continueWithOpen     = true;
  3202.     pPreflightData->wantVScroll            = true;
  3203.     pPreflightData->wantHScroll            = true;
  3204.     pPreflightData->doZoom                = true;
  3205.     pPreflightData->makeProcPtr         = GXMakeWindow;
  3206.     pPreflightData->storageSize         = sizeof(GXDataRecord);
  3207.     
  3208.     return(noErr);
  3209.     
  3210. } // GXPreflightWindow
  3211.  
  3212. // --------------------------------------------------------------------------------------------------------------
  3213.  
  3214. void GXGetFileTypes(OSType * pFileTypes, OSType * pDocumentTypes, short * numTypes)
  3215. {
  3216.     if (gMachineInfo.haveGX)
  3217.         {
  3218.         pFileTypes[*numTypes]         = 'sjob';
  3219.         pDocumentTypes[*numTypes]     = kGXWindow;
  3220.         (*numTypes)++;
  3221.  
  3222.         pFileTypes[*numTypes]         = 'tjob';
  3223.         pDocumentTypes[*numTypes]     = kGXWindow;
  3224.         (*numTypes)++;
  3225.  
  3226.         pFileTypes[*numTypes]         = 'rjob';
  3227.         pDocumentTypes[*numTypes]     = kGXWindow;
  3228.         (*numTypes)++;
  3229.  
  3230.         pFileTypes[*numTypes]         = 'qjob';
  3231.         pDocumentTypes[*numTypes]     = kGXWindow;
  3232.         (*numTypes)++;
  3233.         }
  3234.         
  3235. } // GXGetFileTypes
  3236.